mirror of https://github.com/OISF/suricata
				
				
				
			
			You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			561 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
			
		
		
	
	
			561 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
/*
 | 
						|
 * LibHTP (http://www.libhtp.org)
 | 
						|
 * Copyright 2009,2010 Ivan Ristic <ivanr@webkreator.com>
 | 
						|
 *
 | 
						|
 * LibHTP is an open source product, released under terms of the General Public Licence
 | 
						|
 * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text
 | 
						|
 * of the license.
 | 
						|
 *
 | 
						|
 * In addition, there is a special exception that allows LibHTP to be freely
 | 
						|
 * used with any OSI-approved open source licence. Please refer to the file
 | 
						|
 * LIBHTP_LICENSING_EXCEPTION for the full text of the exception.
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
#include <stdlib.h>
 | 
						|
#include <stdio.h>
 | 
						|
 | 
						|
#include "dslib.h"
 | 
						|
 | 
						|
 | 
						|
// -- Queue List --
 | 
						|
 | 
						|
/**
 | 
						|
 * Add element to list.
 | 
						|
 *
 | 
						|
 * @param list
 | 
						|
 * @param element
 | 
						|
 * @return 1 on success, -1 on error (memory allocation failure)
 | 
						|
 */
 | 
						|
static int list_linked_push(list_t *_q, void *element) {
 | 
						|
    list_linked_t *q = (list_linked_t *) _q;
 | 
						|
    list_linked_element_t *qe = calloc(1, sizeof (list_linked_element_t));
 | 
						|
    if (qe == NULL) return -1;
 | 
						|
 | 
						|
    // Rememeber the element
 | 
						|
    qe->data = element;
 | 
						|
 | 
						|
    // If the queue is empty, make this element first
 | 
						|
    if (!q->first) {
 | 
						|
        q->first = qe;
 | 
						|
    }
 | 
						|
 | 
						|
    if (q->last) {
 | 
						|
        q->last->next = qe;
 | 
						|
    }
 | 
						|
 | 
						|
    q->last = qe;
 | 
						|
 | 
						|
    return 1;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Remove one element from the beginning of the list.
 | 
						|
 *
 | 
						|
 * @param list
 | 
						|
 * @return a pointer to the removed element, or NULL if the list is empty.
 | 
						|
 */
 | 
						|
static void *list_linked_pop(list_t *_q) {
 | 
						|
    list_linked_t *q = (list_linked_t *) _q;
 | 
						|
    void *r = NULL;
 | 
						|
 | 
						|
    if (!q->first) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    list_linked_element_t *qe = q->first;
 | 
						|
    q->first = qe->next;
 | 
						|
    r = qe->data;
 | 
						|
 | 
						|
    if (!q->first) {
 | 
						|
        q->last = NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    free(qe);
 | 
						|
 | 
						|
    return r;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Is the list empty?
 | 
						|
 *
 | 
						|
 * @param list
 | 
						|
 * @return 1 if the list is empty, 0 if it is not
 | 
						|
 */
 | 
						|
static int list_linked_empty(list_t *_q) {
 | 
						|
    list_linked_t *q = (list_linked_t *) _q;
 | 
						|
 | 
						|
    if (!q->first) {
 | 
						|
        return 1;
 | 
						|
    } else {
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Destroy list. This function will not destroy any of the
 | 
						|
 * data stored in it. You'll have to do that manually beforehand.
 | 
						|
 *
 | 
						|
 * @param l
 | 
						|
 */
 | 
						|
void list_linked_destroy(list_linked_t *l) {
 | 
						|
    // Free the list structures
 | 
						|
    list_linked_element_t *temp = l->first;
 | 
						|
    list_linked_element_t *prev = NULL;
 | 
						|
    while (temp != NULL) {
 | 
						|
        free(temp->data);
 | 
						|
        prev = temp;
 | 
						|
        temp = temp->next;
 | 
						|
        free(prev);
 | 
						|
    }
 | 
						|
 | 
						|
    // Free the list itself
 | 
						|
    free(l);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Create a new linked list.
 | 
						|
 *
 | 
						|
 * @return a pointer to the newly creted list (list_t), or NULL on memory allocation failure
 | 
						|
 */
 | 
						|
list_t *list_linked_create(void) {
 | 
						|
    list_linked_t *q = calloc(1, sizeof (list_linked_t));
 | 
						|
    if (q == NULL) return NULL;
 | 
						|
 | 
						|
    q->push = list_linked_push;
 | 
						|
    q->pop = list_linked_pop;
 | 
						|
    q->empty = list_linked_empty;
 | 
						|
    q->destroy = (void (*)(list_t *))list_linked_destroy;
 | 
						|
 | 
						|
    return (list_t *) q;
 | 
						|
}
 | 
						|
 | 
						|
// -- Queue Array --
 | 
						|
 | 
						|
/**
 | 
						|
 * Add new element to the end of the list, expanding the list
 | 
						|
 * as necessary.
 | 
						|
 *
 | 
						|
 * @param list
 | 
						|
 * @param element
 | 
						|
 *
 | 
						|
 * @return 1 on success or -1 on failure (memory allocation)
 | 
						|
 */
 | 
						|
static int list_array_push(list_t *_q, void *element) {
 | 
						|
    list_array_t *q = (list_array_t *) _q;
 | 
						|
 | 
						|
    // Check if we're full
 | 
						|
    if (q->current_size >= q->max_size) {
 | 
						|
        int new_size = q->max_size * 2;
 | 
						|
        void *newblock = NULL;
 | 
						|
        
 | 
						|
        if (q->first == 0) {
 | 
						|
            // The simple case of expansion is when the first
 | 
						|
            // element in the list resides in the first slot. In
 | 
						|
            // that case we just add some new space to the end,
 | 
						|
            // adjust the max_size and that's that.
 | 
						|
            newblock = realloc(q->elements, new_size * sizeof (void *));
 | 
						|
            if (newblock == NULL) return -1;
 | 
						|
        } else {
 | 
						|
            // When the first element is not in the first
 | 
						|
            // memory slot, we need to rearrange the order
 | 
						|
            // of the elements in order to expand the storage area.
 | 
						|
            newblock = malloc(new_size * sizeof (void *));
 | 
						|
            if (newblock == NULL) return -1;
 | 
						|
 | 
						|
            // Copy the beginning of the list to the beginning of the new memory block
 | 
						|
            memcpy(newblock, (char *)q->elements + q->first * sizeof (void *), (q->max_size - q->first) * sizeof (void *));
 | 
						|
            // Append the second part of the list to the end
 | 
						|
            memcpy((char *)newblock + (q->max_size - q->first) * sizeof (void *), q->elements, q->first * sizeof (void *));
 | 
						|
            
 | 
						|
            free(q->elements);
 | 
						|
        }
 | 
						|
        
 | 
						|
        q->first = 0;
 | 
						|
        q->last = q->current_size;
 | 
						|
        q->max_size = new_size;
 | 
						|
        q->elements = newblock;
 | 
						|
    }
 | 
						|
 | 
						|
    q->elements[q->last] = element;
 | 
						|
    q->current_size++;
 | 
						|
    
 | 
						|
    q->last++;
 | 
						|
    if (q->last == q->max_size) {
 | 
						|
        q->last = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    return 1;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Remove one element from the beginning of the list.
 | 
						|
 *
 | 
						|
 * @param list
 | 
						|
 * @return the removed element, or NULL if the list is empty
 | 
						|
 */
 | 
						|
static void *list_array_pop(list_t *_q) {
 | 
						|
    list_array_t *q = (list_array_t *) _q;
 | 
						|
    void *r = NULL;
 | 
						|
 | 
						|
    if (q->current_size == 0) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    r = q->elements[q->first];
 | 
						|
    q->first++;
 | 
						|
    if (q->first == q->max_size) {
 | 
						|
        q->first = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    q->current_size--;
 | 
						|
 | 
						|
    return r;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Returns the size of the list.
 | 
						|
 *
 | 
						|
 * @param list
 | 
						|
 */
 | 
						|
static size_t list_array_size(list_t *_l) {
 | 
						|
    return ((list_array_t *) _l)->current_size;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Return the element at the given index.
 | 
						|
 *
 | 
						|
 * @param list
 | 
						|
 * @param index
 | 
						|
 * @return the desired element, or NULL if the list is too small, or
 | 
						|
 *         if the element at that position carries a NULL
 | 
						|
 */
 | 
						|
static void *list_array_get(list_t *_l, size_t idx) {
 | 
						|
    list_array_t *l = (list_array_t *) _l;
 | 
						|
    void *r = NULL;
 | 
						|
 | 
						|
    if (idx + 1 > l->current_size) return NULL;
 | 
						|
 | 
						|
    size_t i = l->first;
 | 
						|
    r = l->elements[l->first];
 | 
						|
 | 
						|
    while (idx--) {
 | 
						|
        if (++i == l->max_size) {
 | 
						|
            i = 0;
 | 
						|
        }
 | 
						|
 | 
						|
        r = l->elements[i];
 | 
						|
    }
 | 
						|
 | 
						|
    return r;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Replace the element at the given index with the provided element.
 | 
						|
 *
 | 
						|
 * @param list
 | 
						|
 * @param index
 | 
						|
 * @param element
 | 
						|
 *
 | 
						|
 * @return 1 if the element was replaced, or 0 if the list is too small
 | 
						|
 */
 | 
						|
static int list_array_replace(list_t *_l, size_t idx, void *element) {
 | 
						|
    list_array_t *l = (list_array_t *) _l;    
 | 
						|
 | 
						|
    if (idx + 1 > l->current_size) return 0;
 | 
						|
 | 
						|
    size_t i = l->first;
 | 
						|
 | 
						|
    while (idx--) {
 | 
						|
        if (++i == l->max_size) {
 | 
						|
            i = 0;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    l->elements[i] = element;
 | 
						|
 | 
						|
    return 1;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Reset the list iterator.
 | 
						|
 *
 | 
						|
 * @param l
 | 
						|
 */
 | 
						|
void list_array_iterator_reset(list_array_t *l) {
 | 
						|
    l->iterator_index = 0;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Advance to the next list value.
 | 
						|
 *
 | 
						|
 * @param l
 | 
						|
 * @return the next list value, or NULL if there aren't more elements
 | 
						|
 *         left to iterate over or if the element itself is NULL
 | 
						|
 */
 | 
						|
void *list_array_iterator_next(list_array_t *l) {
 | 
						|
    void *r = NULL;
 | 
						|
 | 
						|
    if (l->iterator_index < l->current_size) {
 | 
						|
        r = list_get(l, l->iterator_index);
 | 
						|
        l->iterator_index++;
 | 
						|
    }
 | 
						|
 | 
						|
    return r;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Free the memory occupied by this list. This function assumes
 | 
						|
 * the data elements were freed beforehand.
 | 
						|
 *
 | 
						|
 * @param l
 | 
						|
 */
 | 
						|
void list_array_destroy(list_array_t *l) {
 | 
						|
    free(l->elements);
 | 
						|
    free(l);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Create new array-based list.
 | 
						|
 *
 | 
						|
 * @param size
 | 
						|
 * @return newly allocated list (list_t)
 | 
						|
 */
 | 
						|
list_t *list_array_create(size_t size) {
 | 
						|
    // Allocate the list structure
 | 
						|
    list_array_t *q = calloc(1, sizeof (list_array_t));
 | 
						|
    if (q == NULL) return NULL;
 | 
						|
 | 
						|
    // Allocate the initial batch of elements
 | 
						|
    q->elements = malloc(size * sizeof (void *));
 | 
						|
    if (q->elements == NULL) {
 | 
						|
        free(q);
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    // Initialise structure
 | 
						|
    q->first = 0;
 | 
						|
    q->last = 0;
 | 
						|
    q->max_size = size;
 | 
						|
    q->push = list_array_push;
 | 
						|
    q->pop = list_array_pop;
 | 
						|
    q->get = list_array_get;
 | 
						|
    q->replace = list_array_replace;
 | 
						|
    q->size = list_array_size;
 | 
						|
    q->iterator_reset = (void (*)(list_t *))list_array_iterator_reset;
 | 
						|
    q->iterator_next = (void *(*)(list_t *))list_array_iterator_next;
 | 
						|
    q->destroy = (void (*)(list_t *))list_array_destroy;
 | 
						|
 | 
						|
    return (list_t *) q;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// -- Table --
 | 
						|
 | 
						|
/**
 | 
						|
 * Create a new table structure.
 | 
						|
 *
 | 
						|
 * @param size
 | 
						|
 * @return newly created table_t
 | 
						|
 */
 | 
						|
table_t *table_create(size_t size) {
 | 
						|
    table_t *t = calloc(1, sizeof (table_t));
 | 
						|
    if (t == NULL) return NULL;
 | 
						|
 | 
						|
    // Use a list behind the scenes
 | 
						|
    t->list = list_array_create(size * 2);
 | 
						|
    if (t->list == NULL) {
 | 
						|
        free(t);
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
    
 | 
						|
    return t;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Destroy a table.
 | 
						|
 *
 | 
						|
 * @param table
 | 
						|
 */
 | 
						|
void table_destroy(table_t * table) {
 | 
						|
    // Free keys only
 | 
						|
    int counter = 0;
 | 
						|
    void *data = NULL;
 | 
						|
 | 
						|
    list_iterator_reset(table->list);
 | 
						|
 | 
						|
    while ((data = list_iterator_next(table->list)) != NULL) {
 | 
						|
        // Free key
 | 
						|
        if ((counter % 2) == 0) {
 | 
						|
            free(data);
 | 
						|
        }
 | 
						|
 | 
						|
        counter++;
 | 
						|
    }
 | 
						|
 | 
						|
    list_destroy(table->list);
 | 
						|
 | 
						|
    free(table);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Add a new table element. This function currently makes a copy of
 | 
						|
 * the key, which is inefficient.
 | 
						|
 *
 | 
						|
 * @param table
 | 
						|
 * @param key
 | 
						|
 * @param element
 | 
						|
 */
 | 
						|
int table_add(table_t *table, bstr *key, void *element) {
 | 
						|
    // Lowercase key
 | 
						|
    bstr *lkey = bstr_dup_lower(key);
 | 
						|
    if (lkey == NULL) {
 | 
						|
        return -1;
 | 
						|
    }   
 | 
						|
 | 
						|
    // Add key
 | 
						|
    if (list_add(table->list, lkey) != 1) {
 | 
						|
        free(lkey);
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    // Add element
 | 
						|
    if (list_add(table->list, element) != 1) {
 | 
						|
        list_pop(table->list);
 | 
						|
        free(lkey);
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    return 1;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * @param table
 | 
						|
 * @param key
 | 
						|
 */
 | 
						|
static void *table_get_internal(table_t *table, bstr *key) {
 | 
						|
    // Iterate through the list, comparing
 | 
						|
    // keys with the parameter, return data if found.
 | 
						|
    bstr *ts = NULL;
 | 
						|
    list_iterator_reset(table->list);
 | 
						|
    while ((ts = list_iterator_next(table->list)) != NULL) {
 | 
						|
        void *data = list_iterator_next(table->list);
 | 
						|
        if (bstr_cmp(ts, key) == 0) {
 | 
						|
            return data;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Retrieve the first element in the table with the given
 | 
						|
 * key (as a NUL-terminated string).
 | 
						|
 *
 | 
						|
 * @param table
 | 
						|
 * @param cstr
 | 
						|
 * @return table element, or NULL if not found
 | 
						|
 */
 | 
						|
void *table_getc(table_t *table, char *cstr) {
 | 
						|
    // TODO This is very inefficient
 | 
						|
    bstr *key = bstr_cstrdup(cstr);
 | 
						|
    if (key == NULL)
 | 
						|
        return NULL;
 | 
						|
    bstr_tolowercase(key);
 | 
						|
    void *data = table_get_internal(table, key);
 | 
						|
    free(key);
 | 
						|
    return data;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Retrieve the first element in the table with the given key.
 | 
						|
 *
 | 
						|
 * @param table
 | 
						|
 * @param key
 | 
						|
 * @return table element, or NULL if not found
 | 
						|
 */
 | 
						|
void *table_get(table_t *table, bstr *key) {
 | 
						|
    if (table == NULL)
 | 
						|
        return NULL;
 | 
						|
    // TODO This is very inefficient
 | 
						|
    bstr *lkey = bstr_dup_lower(key);
 | 
						|
    if (lkey == NULL)
 | 
						|
        return NULL;
 | 
						|
    void *data = table_get_internal(table, lkey);
 | 
						|
    free(lkey);
 | 
						|
    return data;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Reset the table iterator.
 | 
						|
 *
 | 
						|
 * @param table
 | 
						|
 */
 | 
						|
void table_iterator_reset(table_t *table) {
 | 
						|
    list_iterator_reset(table->list);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Advance to the next table element.
 | 
						|
 *
 | 
						|
 * @param t
 | 
						|
 * @param data
 | 
						|
 * @return pointer to the key and the element if there is a next element, NULL otherwise
 | 
						|
 */
 | 
						|
bstr *table_iterator_next(table_t *t, void **data) {
 | 
						|
    bstr *s = list_iterator_next(t->list);
 | 
						|
    if (s != NULL) {
 | 
						|
        *data = list_iterator_next(t->list);
 | 
						|
    }
 | 
						|
 | 
						|
    return s;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Returns the size of the table.
 | 
						|
 *
 | 
						|
 * @param table
 | 
						|
 * @return table size
 | 
						|
 */
 | 
						|
size_t table_size(table_t *table) {
 | 
						|
    return list_size(table->list) / 2;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Remove all elements from the table.
 | 
						|
 *
 | 
						|
 * @param table
 | 
						|
 */
 | 
						|
void table_clear(table_t *table) {    
 | 
						|
    // TODO Clear table by removing the existing elements
 | 
						|
    
 | 
						|
    size_t size = list_size(table->list);
 | 
						|
 | 
						|
    list_destroy(table->list);
 | 
						|
    
 | 
						|
    // Use a list behind the scenes
 | 
						|
    table->list = list_array_create(size == 0 ? 10 : size);
 | 
						|
    if (table->list == NULL) {
 | 
						|
        free(table);        
 | 
						|
    }    
 | 
						|
}
 | 
						|
 | 
						|
#if 0
 | 
						|
 | 
						|
int main(int argc, char **argv) {
 | 
						|
    list_t *q = list_linked_create();
 | 
						|
 | 
						|
    list_push(q, "1");
 | 
						|
    list_push(q, "2");
 | 
						|
    list_push(q, "3");
 | 
						|
    list_push(q, "4");
 | 
						|
 | 
						|
    char *s = NULL;
 | 
						|
    while ((s = (char *) list_pop(q)) != NULL) {
 | 
						|
        printf("Got: %s\n", s);
 | 
						|
    }
 | 
						|
 | 
						|
    free(q);
 | 
						|
}
 | 
						|
#endif
 |