Importing all of DRL, including ulogd and all of its files.
[distributedratelimiting.git] / drl / util.c
diff --git a/drl/util.c b/drl/util.c
new file mode 100644 (file)
index 0000000..9f5706a
--- /dev/null
@@ -0,0 +1,360 @@
+/* See the DRL-LICENSE file for this file's software license. */
+
+/* util.c
+ *
+ * Mainly a hash table implementation, but other sundry items for
+ * ulogd_DRL as well.
+ * Ken Yocum 2007/08
+ */
+
+#include "raterouter.h"
+#include "util.h"
+#include "ratetypes.h"
+#include "logging.h"
+
+static int util_salt = 0;
+
+/* stupidity BE:MSB first, LE: MSB last*/
+static int am_big_endian(void){
+    long one = 1;
+    return !(*((char*)(&one))); /* looking for 1 in the big end */
+}
+
+static int compare_key(void *one, void *two, int len){
+    int i;
+    for (i=0;i<len;i++){ /* word-wise bit compare would be faster */
+        if(((char*)one)[i] != ((char*)two)[i]){
+            return(false);
+        }
+    }
+    return(true);
+}
+
+/* pass in something at least 20 bytes long */
+void ip_from_bytes(uint32_t addr, char *buf){
+    int i;
+    unsigned char *caddr = (unsigned char*) &addr;
+    if (am_big_endian()){
+        i = sprintf(buf,"%d.%d.%d.%d",caddr[0],caddr[1],caddr[2],caddr[3]);
+    } else {
+        i = sprintf(buf,"%d.%d.%d.%d",caddr[3],caddr[2],caddr[1],caddr[0]);
+    }
+    return;
+}
+
+
+void init_hashing(void){
+    util_salt = getpid() ^ time(NULL); // same as ulogd_drl
+}
+
+/* some stupid generic hash function things */
+/* just return a map_handle */
+map_handle allocate_map(void) {
+    map_handle map;
+    map = (map_handle) malloc(sizeof(struct map));
+    if (map == NULL) {
+        printlog(LOG_WARN, "allocate_map failed.");
+        return NULL;
+    }
+
+    memset(map,0,sizeof(struct map));
+    map->iterator = map->table[0];
+    map->size = 0;
+    return(map);
+}
+
+/* de-allocates the map, if true, de-allocates crud in map as well */
+void free_map(map_handle map, int dealloc){
+    int i;
+    struct map_entry *nxt_me,*tmp;
+    for (i=0;i<GENERIC_HASH_SIZE;i++){
+        nxt_me = (struct map_entry*) (map->table[i]);
+        while(nxt_me) {
+            if (dealloc && (nxt_me->value != NULL)){
+                free(nxt_me->value);
+                nxt_me->value=NULL;
+            }
+            tmp = nxt_me->nxt;
+            free(nxt_me);
+            map->size--;
+            nxt_me= tmp;
+        }
+    }
+    free(map);
+}
+
+/* internal_search
+ * 
+ * prior_me points to a pointer for the space holding the next map
+ * entry
+ * If you find the first entry of the linked list, it points to the
+ * memory in the table holding the pointer to the first map entry.
+ * Otherwise it points to the memory in the previous map_entry that
+ * holds the next pointer.
+ * A triple pointer here, b/c we need to save the value.  
+ */
+static struct map_entry* internal_search(map_handle map, void *key, int keylen, struct map_entry*** prior_me){
+    uint32_t index;
+    struct map_entry *nxt_me;
+
+    index = jhash(key,keylen,util_salt) & (GENERIC_HASH_SIZE - 1);
+
+#if 0
+    printf("IS: KEY:");
+    for(i=0;i<keylen;i++){
+        printf("[%x]",((char*)key)[i]);
+    }
+    printf("    Hashes to index (%d)\n", index);
+#endif
+
+    nxt_me = (struct map_entry*) map->table[index];
+    *prior_me = (struct map_entry**) &(map->table[index]);
+
+    while(nxt_me){
+        if (compare_key(nxt_me->key,key,keylen)){
+            return(nxt_me);
+        }
+        *prior_me = &(nxt_me->nxt);
+        nxt_me = nxt_me->nxt;
+    }
+    return(NULL);
+
+}
+
+void* map_next(map_handle map){
+    void *val;
+
+    if (map->iterator_row == GENERIC_HASH_SIZE){
+        return(NULL); /* empty, call reset */
+    }
+    /* iterator points to current one to return */
+    if (map->iterator != NULL){
+        val = map->iterator->value;
+        map->iterator = map->iterator->nxt;
+        return(val);
+    }
+    /* if null, go to next row */
+    while (map->iterator == NULL){
+        map->iterator_row++;
+        if (map->iterator_row < GENERIC_HASH_SIZE) {
+            map->iterator = map->table[map->iterator_row];
+        } else {
+            return(NULL);
+        }
+    }
+    val = map->iterator->value;
+    map->iterator = map->iterator->nxt;
+    return(val);
+}
+
+void map_reset_iterate(map_handle map){
+    map->iterator = map->table[0];
+    map->iterator_row = 0;
+}
+
+int map_size(map_handle map){
+    return(map->size);
+}
+
+void** map_to_array(map_handle map, int *length){
+    void** array = (void**)malloc(sizeof(void*)*(map->size + 1));
+    int i;
+
+    *length = map->size;
+    map_reset_iterate(map);
+    for(i=0;i<map->size;i++){
+        array[i] = map_next(map);
+    }
+    array[i] = NULL; /* just in case */
+    return(array);
+}
+
+void* map_search(map_handle map,void *key, int keylen){
+    struct map_entry *me,**pme;
+    me = internal_search(map,key,keylen,&pme);
+    if (me!=NULL) {
+        return(me->value);
+    } else {
+        return(NULL);
+    }
+}
+
+void* map_remove(map_handle map,void *key, int keylen){
+    struct map_entry *me,**pme;
+    void *rtn_val;
+    me = internal_search(map,key,keylen,&pme);
+    if (me!=NULL){
+        (*pme) = me->nxt;
+        rtn_val = me->value;
+        free (me);
+        map->size--;
+        return(rtn_val);
+    } else {
+        return(NULL);
+    }
+}
+
+/* the key is a void *, but we also need the length */
+void map_insert(map_handle map, void *key, int keylen, void *value) {
+    struct map_entry *me,**pme;
+
+    me = internal_search(map,key,keylen,&pme);
+    if (me != NULL){
+        printlog(LOG_WARN, "util.c: insert failed, key already present.");
+        return;
+    }
+    /* now pme is at the end of the list on that index */
+    me = (struct map_entry*) malloc(sizeof(struct map_entry));
+    if (me == NULL) {
+        printlog(LOG_WARN, "util.c: insert failed, malloc failure");
+        return;
+    }
+    if ((*pme) == NULL)
+        (*pme) = me; /* pointer now points to this new entry */
+    else {
+        printlog(LOG_WARN, "util.c: insert failed. pme should always be NULL.");
+        free(me);
+        return;
+    }
+    me->nxt = NULL;
+    me->key = key;
+    me->value = value;
+    map->size++;
+    return;
+}
+
+/* get_local_ip
+ *
+ * go through the available interfaces and find the first 
+ * with a routable IP (not 10.*, 192.*, or 172.*) 
+ * Ignore inet6 addrs for now. 
+ * return the string. 
+ */
+char* get_local_ip(){
+    char *ip;
+    struct ifaddrs *ifa = NULL, *ifp = NULL;
+    struct sockaddr *addr;
+    uint32_t ho_addr;
+    socklen_t salen;
+    int shift;
+    unsigned char addrbyte;
+
+
+    if (getifaddrs(&ifp) < 0) {
+        perror("getifaddrs");
+        return 0;
+    }
+
+    if (am_big_endian()){
+        shift = 0;
+    } else {
+        shift = 3;
+    }
+
+#define STRINGSIZE 200
+    ip = (char *)malloc(STRINGSIZE);
+
+
+    for (ifa = ifp; ifa; ifa=ifa->ifa_next){
+        if (ifa->ifa_addr->sa_family == AF_INET){
+            salen = sizeof(struct sockaddr_in);
+        } else if( ifa->ifa_addr->sa_family == AF_INET6){
+            salen = sizeof(struct sockaddr_in6);
+        } else {
+            continue;
+        }
+
+
+        if (getnameinfo(ifa->ifa_addr,salen, ip, STRINGSIZE, NULL, 0, NI_NUMERICHOST) < 0){
+            perror("getnameinfo");
+            continue;
+        }
+        /* return the first public IP match */
+
+        addr = ifa->ifa_addr;  /* a sockaddr */
+        struct in_addr *sin_addr = & (((struct sockaddr_in*)addr)->sin_addr); 
+        ho_addr = ntohl((uint32_t)(sin_addr->s_addr));
+        addrbyte = ((char*)&ho_addr)[shift];
+        //printf("get_local_ip found %s and sin_addr 0x%x addrbyte %d\n",ip,ho_addr,(uint32_t)addrbyte);
+
+        /* is it MSB first? */
+
+        if ( (addrbyte != 192) && (addrbyte != 172) 
+                && (addrbyte != 10) && (addrbyte != 127) ){
+            printlog(LOG_WARN, "     Using ip: %s\n",ip);
+            freeifaddrs(ifp);
+#if 0
+            return (ifa->ifa_addr->sin_addr);
+#else 
+            return(ip); /* for now return the IP address */
+#endif
+        }
+    }
+    freeifaddrs(ifp);
+    free(ip);
+    return(NULL);
+}
+
+static FILE *urandfd = NULL;
+
+static void myrand_init() {
+    if (urandfd == NULL) {
+        urandfd = fopen("/dev/urandom", "rb");
+        if (urandfd == NULL) {
+            perror("myrand_init: fopen");
+        }
+        setvbuf(urandfd, NULL, _IOFBF, 1 << 16);
+    }
+}
+
+/* returns an unsigned int between 0 and UINT_MAX */
+unsigned int myrand() {
+    int successful;
+
+    /* my new rand code */
+    myrand_init();
+
+    unsigned int r;  
+    successful = fread(&r, sizeof(unsigned int), 1, urandfd);
+
+    return r;
+}
+
+/* returns a random bool */
+int myrand_boolean() {
+    int successful;
+
+    myrand_init();
+
+    uint8_t r;
+    successful = fread(&r, sizeof(uint8_t), 1, urandfd);
+
+    return (r%2);
+}
+
+/* returns a random double between 0 and 1 */
+double myrand_double() {
+    return (double) myrand() / (double) UINT_MAX;
+}
+
+/* takes the log_2 of x */
+int my_lg(int x) {
+    int c = 0;
+    while (x > 0) {
+        c++;
+        x = x >> 1;
+    }
+
+    return c;
+}
+
+/* print out some error information if a system call failes */
+void print_system_error(int ret){
+    if (WIFSIGNALED(ret) &&
+            (WTERMSIG(ret) == SIGINT || WTERMSIG(ret) == SIGQUIT)){
+        /* received some kind of signal during program execution */
+        printf("enforce received signal during program execution.");
+    } else {
+        perror("enforce failed (ret==-1):");
+    }
+}