Cite the source of frequency allocation information.
[obnox/wireshark/wip.git] / epan / emem.c
index 30312b0bad0e2f6f5fa61fe2bf962d47ae5ab609..c142a9d4fbd8e85728381854e7e8e5920fee2515 100644 (file)
@@ -30,6 +30,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
+#include <ctype.h>
 
 #include <time.h>
 #ifdef HAVE_SYS_TIME_H
 #include <unistd.h>
 #endif
 
-#ifdef _WIN32
-#include <windows.h>   /* VirtualAlloc, VirtualProtect */
-#include <process.h>    /* getpid */
-#endif
-
 #include <glib.h>
 #include <proto.h>
 #include "emem.h"
 #include <wiretap/file_util.h>
 
+#ifdef _WIN32
+#include <windows.h>   /* VirtualAlloc, VirtualProtect */
+#include <process.h>    /* getpid */
+#endif
+
 
 /*
  * Tools like Valgrind and ElectricFence don't work well with memchunks.
@@ -65,7 +66,6 @@
 /* Do we want to use canaries ? */
 #define DEBUG_USE_CANARIES 1
 
-
 #ifdef WANT_GUARD_PAGES
 /* Add guard pages at each end of our allocated memory */
 #if defined(HAVE_SYSCONF) && defined(HAVE_MMAP) && defined(HAVE_MPROTECT) && defined(HAVE_STDINT_H)
@@ -125,8 +125,8 @@ typedef struct _emem_header_t {
   emem_chunk_t *used_list;
 } emem_header_t;
 
-static emem_header_t ep_packet_mem;
-static emem_header_t se_packet_mem;
+emem_header_t ep_packet_mem;
+emem_header_t se_packet_mem;
 
 #if !defined(SE_DEBUG_FREE)
 #if defined (_WIN32)
@@ -164,7 +164,7 @@ emem_canary(guint8 *canary) {
        size_t sz;
        /* Try /dev/urandom */
        if ((fp = eth_fopen("/dev/urandom", "r")) != NULL) {
-               sz = fread(canary, EMEM_CANARY_DATA_SIZE, 1, fp);
+         sz = fread(canary, 1, EMEM_CANARY_DATA_SIZE, fp);
                fclose(fp);
                if (sz == EMEM_CANARY_SIZE) {
                        return;
@@ -288,7 +288,9 @@ emem_create_chunk(emem_chunk_t **free_list) {
                /* 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);
+                if(npc->buf == NULL) {
+                    THROW(OutOfMemoryError);
+               }
                buf_end = npc->buf + EMEM_PACKET_CHUNK_SIZE;
 
                /* Align our guard pages on page-sized boundaries */
@@ -308,7 +310,10 @@ emem_create_chunk(emem_chunk_t **free_list) {
 #elif defined(USE_GUARD_PAGES)
                npc->buf = mmap(NULL, EMEM_PACKET_CHUNK_SIZE,
                        PROT_READ|PROT_WRITE, ANON_PAGE_MODE, ANON_FD, 0);
-               g_assert(npc->buf != MAP_FAILED);
+                if(npc->buf == MAP_FAILED) {
+                    /* XXX - what do we have to cleanup here? */
+                    THROW(OutOfMemoryError);
+               }
                buf_end = npc->buf + EMEM_PACKET_CHUNK_SIZE;
 
                /* Align our guard pages on page-sized boundaries */
@@ -325,11 +330,14 @@ emem_create_chunk(emem_chunk_t **free_list) {
                npc->free_offset = npc->free_offset_init;
 
 #else /* Is there a draft in here? */
+               npc->buf = malloc(EMEM_PACKET_CHUNK_SIZE);
+                if(npc->buf == NULL) {
+                    THROW(OutOfMemoryError);
+               }
                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 */
        }
 }
@@ -504,7 +512,7 @@ gchar* ep_strndup(const gchar* src, size_t len) {
        gchar* dst = ep_alloc(len+1);
        guint i;
 
-       for (i = 0; src[i] && i < len; i++)
+       for (i = 0; (i < len) && src[i]; i++)
                dst[i] = src[i];
 
        dst[i] = '\0';
@@ -646,7 +654,7 @@ gchar* se_strndup(const gchar* src, size_t len) {
        gchar* dst = se_alloc(len+1);
        guint i;
 
-       for (i = 0; src[i] && i < len; i++)
+       for (i = 0; (i < len) && src[i]; i++)
                dst[i] = src[i];
 
        dst[i] = '\0';
@@ -744,7 +752,6 @@ se_free_all(void)
 #endif /* DEBUG_USE_CANARIES */
 #endif
 
-
        /* move all used chunks over to the free list */
        while(se_packet_mem.used_list){
                npc=se_packet_mem.used_list;
@@ -859,7 +866,7 @@ void print_tree(emem_tree_node_t *node){
 emem_tree_t *se_trees=NULL;
 
 emem_tree_t *
-se_tree_create(int type, char *name)
+se_tree_create(int type, const char *name)
 {
        emem_tree_t *tree_list;
 
@@ -877,7 +884,7 @@ se_tree_create(int type, char *name)
 
 
 void *
-se_tree_lookup32(emem_tree_t *se_tree, guint32 key)
+emem_tree_lookup32(emem_tree_t *se_tree, guint32 key)
 {
        emem_tree_node_t *node;
 
@@ -900,7 +907,7 @@ se_tree_lookup32(emem_tree_t *se_tree, guint32 key)
 }
 
 void *
-se_tree_lookup32_le(emem_tree_t *se_tree, guint32 key)
+emem_tree_lookup32_le(emem_tree_t *se_tree, guint32 key)
 {
        emem_tree_node_t *node;
 
@@ -1156,7 +1163,7 @@ rb_insert_case1(emem_tree_t *se_tree, emem_tree_node_t *node)
 /* insert a new node in the tree. if this node matches an already existing node
  * then just replace the data for that node */
 void
-se_tree_insert32(emem_tree_t *se_tree, guint32 key, void *data)
+emem_tree_insert32(emem_tree_t *se_tree, guint32 key, void *data)
 {
        emem_tree_node_t *node;
 
@@ -1175,6 +1182,7 @@ se_tree_insert32(emem_tree_t *se_tree, guint32 key, void *data)
                node->right=NULL;
                node->key32=key;
                node->data=data;
+               node->u.is_subtree = EMEM_TREE_NODE_IS_DATA;
                se_tree->tree=node;
                return;
        }
@@ -1199,6 +1207,7 @@ se_tree_insert32(emem_tree_t *se_tree, guint32 key, void *data)
                                new_node->right=NULL;
                                new_node->key32=key;
                                new_node->data=data;
+                               new_node->u.is_subtree=EMEM_TREE_NODE_IS_DATA;
                                node=new_node;
                                break;
                        }
@@ -1216,6 +1225,7 @@ se_tree_insert32(emem_tree_t *se_tree, guint32 key, void *data)
                                new_node->right=NULL;
                                new_node->key32=key;
                                new_node->data=data;
+                               new_node->u.is_subtree=EMEM_TREE_NODE_IS_DATA;
                                node=new_node;
                                break;
                        }
@@ -1233,7 +1243,7 @@ se_tree_insert32(emem_tree_t *se_tree, guint32 key, void *data)
        }
 }
 
-static void* lookup_or_insert32(emem_tree_t *se_tree, guint32 key, void*(*func)(void*),void* ud) {
+static void* lookup_or_insert32(emem_tree_t *se_tree, guint32 key, void*(*func)(void*),void* ud, int is_subtree) {
        emem_tree_node_t *node;
 
        node=se_tree->tree;
@@ -1251,6 +1261,7 @@ static void* lookup_or_insert32(emem_tree_t *se_tree, guint32 key, void*(*func)(
                node->right=NULL;
                node->key32=key;
                node->data= func(ud);
+               node->u.is_subtree = is_subtree;
                se_tree->tree=node;
                return node->data;
        }
@@ -1274,6 +1285,7 @@ static void* lookup_or_insert32(emem_tree_t *se_tree, guint32 key, void*(*func)(
                                new_node->right=NULL;
                                new_node->key32=key;
                                new_node->data= func(ud);
+                               new_node->u.is_subtree = is_subtree;
                                node=new_node;
                                break;
                        }
@@ -1291,6 +1303,7 @@ static void* lookup_or_insert32(emem_tree_t *se_tree, guint32 key, void*(*func)(
                                new_node->right=NULL;
                                new_node->key32=key;
                                new_node->data= func(ud);
+                               new_node->u.is_subtree = is_subtree;
                                node=new_node;
                                break;
                        }
@@ -1314,7 +1327,7 @@ static void* lookup_or_insert32(emem_tree_t *se_tree, guint32 key, void*(*func)(
  * never existed including all metadata associated with the tree.
  */
 emem_tree_t *
-se_tree_create_non_persistent(int type, char *name)
+se_tree_create_non_persistent(int type, const char *name)
 {
        emem_tree_t *tree_list;
 
@@ -1328,16 +1341,51 @@ se_tree_create_non_persistent(int type, char *name)
        return tree_list;
 }
 
+/* This tree is PErmanent and will never be released
+ */
+emem_tree_t *
+pe_tree_create(int type, char *name)
+{
+       emem_tree_t *tree_list;
+
+       tree_list=g_malloc(sizeof(emem_tree_t));
+       tree_list->next=NULL;
+       tree_list->type=type;
+       tree_list->tree=NULL;
+       tree_list->name=name;
+       tree_list->malloc=(void *(*)(size_t)) g_malloc;
+
+       return tree_list;
+}
+
+/* create another (sub)tree using the same memory allocation scope
+ * as the parent tree.
+ */
+static emem_tree_t *
+emem_tree_create_subtree(emem_tree_t *parent_tree, char *name)
+{
+       emem_tree_t *tree_list;
+
+       tree_list=parent_tree->malloc(sizeof(emem_tree_t));
+       tree_list->next=NULL;
+       tree_list->type=parent_tree->type;
+       tree_list->tree=NULL;
+       tree_list->name=name;
+       tree_list->malloc=parent_tree->malloc;
+
+       return tree_list;
+}
+
 static void* create_sub_tree(void* d) {
        emem_tree_t *se_tree = d;
-       return se_tree_create_non_persistent(se_tree->type, "subtree");
+       return emem_tree_create_subtree(se_tree, "subtree");
 }
 
 /* insert a new node in the tree. if this node matches an already existing node
  * then just replace the data for that node */
 
 void
-se_tree_insert32_array(emem_tree_t *se_tree, emem_tree_key_t *key, void *data)
+emem_tree_insert32_array(emem_tree_t *se_tree, emem_tree_key_t *key, void *data)
 {
        emem_tree_t *next_tree;
 
@@ -1345,11 +1393,11 @@ se_tree_insert32_array(emem_tree_t *se_tree, emem_tree_key_t *key, void *data)
                DISSECTOR_ASSERT_NOT_REACHED();
        }
        if((key[0].length==1)&&(key[1].length==0)){
-               se_tree_insert32(se_tree, *key[0].key, data);
+               emem_tree_insert32(se_tree, *key[0].key, data);
                return;
        }
 
-       next_tree=lookup_or_insert32(se_tree, *key[0].key, create_sub_tree, se_tree);
+       next_tree=lookup_or_insert32(se_tree, *key[0].key, create_sub_tree, se_tree, EMEM_TREE_NODE_IS_SUBTREE);
 
        if(key[0].length==1){
                key++;
@@ -1357,11 +1405,11 @@ se_tree_insert32_array(emem_tree_t *se_tree, emem_tree_key_t *key, void *data)
                key[0].length--;
                key[0].key++;
        }
-       se_tree_insert32_array(next_tree, key, data);
+       emem_tree_insert32_array(next_tree, key, data);
 }
 
 void *
-se_tree_lookup32_array(emem_tree_t *se_tree, emem_tree_key_t *key)
+emem_tree_lookup32_array(emem_tree_t *se_tree, emem_tree_key_t *key)
 {
        emem_tree_t *next_tree;
 
@@ -1369,9 +1417,9 @@ se_tree_lookup32_array(emem_tree_t *se_tree, emem_tree_key_t *key)
                DISSECTOR_ASSERT_NOT_REACHED();
        }
        if((key[0].length==1)&&(key[1].length==0)){
-               return se_tree_lookup32(se_tree, *key[0].key);
+               return emem_tree_lookup32(se_tree, *key[0].key);
        }
-       next_tree=se_tree_lookup32(se_tree, *key[0].key);
+       next_tree=emem_tree_lookup32(se_tree, *key[0].key);
        if(!next_tree){
                return NULL;
        }
@@ -1381,86 +1429,199 @@ se_tree_lookup32_array(emem_tree_t *se_tree, emem_tree_key_t *key)
                key[0].length--;
                key[0].key++;
        }
-       return se_tree_lookup32_array(next_tree, key);
+       return emem_tree_lookup32_array(next_tree, key);
 }
 
 
-void se_tree_insert_string(emem_string_hash_t* se_tree, const gchar* k, void* v) {
+/* Strings are stored as an array of uint32 containing the string characters
+   with 4 characters in each uint32. 
+   The first byte of the string is stored as the most significant byte.
+   If the string is not a multiple of 4 characters in length the last
+   uint32 containing the string bytes are padded with 0 bytes.
+   After the uint32's containing the string, there is one final terminator
+   uint32 with the value 0x00000001
+*/
+void
+emem_tree_insert_string(emem_tree_t* se_tree, const gchar* k, void* v, guint32 flags)
+{
+       emem_tree_key_t key[2];
+       guint32 *aligned=NULL;
        guint32 len = strlen(k);
-       guint32 div = (len-1)/4;
-       guint32 residual = 0;
-       emem_tree_key_t key[] = {
-               {1,NULL},
-               {0,NULL},
-               {1,NULL},
-               {0,NULL}
-       };
-
-       key[0].key = &len;
-       key[1].length = div;
-       key[1].key = (guint32*)(&k[0]);
-       key[2].key = &residual;
-
-       if (! div) {
-               key[1].length = key[2].length;
-               key[1].key = key[2].key;
-               key[2].length = 0;
-               key[2].key = NULL;
-       }
+       guint32 div = (len+3)/4+1;
+       guint32 i;
+       guint32 tmp;
 
-       div *= 4;
-
-       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;
+       aligned = malloc(div * sizeof (guint32));
+
+       /* pack the bytes one one by one into guint32s */
+       tmp = 0;
+       for (i = 0;i < len;i++) {
+               unsigned char ch;
+
+               ch = (unsigned char)k[i];
+               if (flags & EMEM_TREE_STRING_NOCASE) {
+                       if(isupper(ch)) {
+                               ch = tolower(ch);
+                       }
+               }
+               tmp <<= 8;
+               tmp |= ch;
+               if (i%4 == 3) {
+                       aligned[i/4] = tmp;
+                       tmp = 0;
+               }               
+       }
+       /* add required padding to the last uint32 */
+       if (i%4 != 0) {
+               while (i%4 != 0) {
+                       i++;
+                       tmp <<= 8;
+               }
+               aligned[i/4-1] = tmp;
        }
+       
+       /* add the terminator */
+       aligned[div-1] = 0x00000001;
 
-       se_tree_insert32_array(se_tree,key,v);
+       key[0].length = div;
+       key[0].key = aligned;
+       key[1].length = 0;
+       key[1].key = NULL;
+
+
+       emem_tree_insert32_array(se_tree, key, v);
+       free(aligned);
 }
 
-void* se_tree_lookup_string(emem_string_hash_t* se_tree, const gchar* k) {
+void *
+emem_tree_lookup_string(emem_tree_t* se_tree, const gchar* k, guint32 flags)
+{
+       emem_tree_key_t key[2];
+       guint32 *aligned=NULL;
        guint32 len = strlen(k);
-       guint32 div = (len-1)/4;
-       guint32 residual = 0;
-       emem_tree_key_t key[] = {
-               {1,NULL},
-               {0,NULL},
-               {1,NULL},
-               {0,NULL}
-       };
-
-       key[0].key = &len;
-       key[1].length = div;
-       key[1].key = (guint32*)(&k[0]);
-       key[2].key = &residual;
-
-       if (! div) {
-               key[1].length = key[2].length;
-               key[1].key = key[2].key;
-               key[2].length = 0;
-               key[2].key = NULL;
+       guint32 div = (len+3)/4+1;
+       guint32 i;
+       guint32 tmp;
+       void *ret;
+
+       aligned = malloc(div * sizeof (guint32));
+
+       /* pack the bytes one one by one into guint32s */
+       tmp = 0;
+       for (i = 0;i < len;i++) {
+               unsigned char ch;
+
+               ch = (unsigned char)k[i];
+               if (flags & EMEM_TREE_STRING_NOCASE) {
+                       if(isupper(ch)) {
+                               ch = tolower(ch);
+                       }
+               }
+               tmp <<= 8;
+               tmp |= ch;
+               if (i%4 == 3) {
+                       aligned[i/4] = tmp;
+                       tmp = 0;
+               }               
        }
+       /* add required padding to the last uint32 */
+       if (i%4 != 0) {
+               while (i%4 != 0) {
+                       i++;
+                       tmp <<= 8;
+               }
+               aligned[i/4-1] = tmp;
+       }
+       
+       /* add the terminator */
+       aligned[div-1] = 0x00000001;
 
-       div *= 4;
-
-       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;
+       key[0].length = div;
+       key[0].key = aligned;
+       key[1].length = 0;
+       key[1].key = NULL;
+
+
+       ret = emem_tree_lookup32_array(se_tree, key);
+       free(aligned);
+       return ret;
+}
+
+static gboolean
+emem_tree_foreach_nodes(emem_tree_node_t* node, tree_foreach_func callback, void *user_data)
+{
+       gboolean stop_traverse = FALSE;
+
+       if (!node)
+               return FALSE;
+
+       if(node->left) {
+               stop_traverse = emem_tree_foreach_nodes(node->left, callback, user_data);
+               if (stop_traverse) {
+                       return TRUE;
+               }
+       }
+
+       if (node->u.is_subtree == EMEM_TREE_NODE_IS_SUBTREE) {
+               stop_traverse = emem_tree_foreach(node->data, callback, user_data);
+       } else {
+               stop_traverse = callback(node->data, user_data);
+       }
+
+       if (stop_traverse) {
+               return TRUE;
+       }
+
+       if(node->right) {
+               stop_traverse = emem_tree_foreach_nodes(node->right, callback, user_data);
+               if (stop_traverse) {
+                       return TRUE;
+               }
        }
 
-       return se_tree_lookup32_array(se_tree, key);
+       return FALSE;
+}
+
+gboolean
+emem_tree_foreach(emem_tree_t* emem_tree, tree_foreach_func callback, void *user_data)
+{
+       if (!emem_tree)
+               return FALSE;
+
+       if(!emem_tree->tree)
+               return FALSE;
+
+       return emem_tree_foreach_nodes(emem_tree->tree, callback, user_data);
+}
+
+
+static void
+emem_tree_print_nodes(emem_tree_node_t* node, int level)
+{
+       int i;
+
+       if (!node)
+               return;
+
+       for(i=0;i<level;i++){
+               printf("    ");
+       }
+
+       printf("NODE:%p parent:%p left:0x%p right:%px key:%d data:%p\n",
+               (void *)node,(void *)(node->parent),(void *)(node->left),(void *)(node->right),
+               (node->key32),node->data);
+       if(node->left)
+               emem_tree_print_nodes(node->left, level+1);
+       if(node->right)
+               emem_tree_print_nodes(node->right, level+1);
+}
+void
+emem_print_tree(emem_tree_t* emem_tree)
+{
+       if (!emem_tree)
+               return;
+
+       printf("EMEM tree type:%d name:%s tree:%p\n",emem_tree->type,emem_tree->name,(void *)(emem_tree->tree));
+       if(emem_tree->tree)
+               emem_tree_print_nodes(emem_tree->tree, 0);
 }