/* 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;iiterator = 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;itable[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;itable[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;isize;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):"); } }