📄 dict.c
字号:
/* * dict.c Routines to read the dictionary file. * * Version: $Id: dict.c,v 1.111 2007/12/17 12:29:30 aland Exp $ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * Copyright 2000,2006 The FreeRADIUS server project */#include <freeradius-devel/ident.h>RCSID("$Id: dict.c,v 1.111 2007/12/17 12:29:30 aland Exp $")#include <freeradius-devel/libradius.h>#include <ctype.h>#ifdef HAVE_MALLOC_H#include <malloc.h>#endif#ifdef HAVE_SYS_STAT_H#include <sys/stat.h>#endif#define DICT_VALUE_MAX_NAME_LEN (128)#define DICT_VENDOR_MAX_NAME_LEN (128)static fr_hash_table_t *vendors_byname = NULL;static fr_hash_table_t *vendors_byvalue = NULL;static fr_hash_table_t *attributes_byname = NULL;static fr_hash_table_t *attributes_byvalue = NULL;static fr_hash_table_t *values_byvalue = NULL;static fr_hash_table_t *values_byname = NULL;static DICT_ATTR *dict_base_attrs[256];/* * For faster HUP's, we cache the stat information for * files we've $INCLUDEd */typedef struct dict_stat_t { struct dict_stat_t *next; char *name; time_t mtime;} dict_stat_t;static char *stat_root_dir = NULL;static char *stat_root_file = NULL;static dict_stat_t *stat_head = NULL;static dict_stat_t *stat_tail = NULL;typedef struct value_fixup_t { char attrstr[40]; DICT_VALUE *dval; struct value_fixup_t *next;} value_fixup_t;/* * So VALUEs in the dictionary can have forward references. */static value_fixup_t *value_fixup = NULL;static const FR_NAME_NUMBER type_table[] = { { "integer", PW_TYPE_INTEGER }, { "string", PW_TYPE_STRING }, { "ipaddr", PW_TYPE_IPADDR }, { "date", PW_TYPE_DATE }, { "abinary", PW_TYPE_ABINARY }, { "octets", PW_TYPE_OCTETS }, { "ifid", PW_TYPE_IFID }, { "ipv6addr", PW_TYPE_IPV6ADDR }, { "ipv6prefix", PW_TYPE_IPV6PREFIX }, { "byte", PW_TYPE_BYTE }, { "short", PW_TYPE_SHORT }, { "ether", PW_TYPE_ETHERNET }, { NULL, 0 }};/* * Create the hash of the name. * * We copy the hash function here because it's substantially faster. */#define FNV_MAGIC_INIT (0x811c9dc5)#define FNV_MAGIC_PRIME (0x01000193)static uint32_t dict_hashname(const char *name){ uint32_t hash = FNV_MAGIC_INIT; const char *p; for (p = name; *p != '\0'; p++) { int c = *(const unsigned char *) p; if (isalpha(c)) c = tolower(c); hash *= FNV_MAGIC_PRIME; hash ^= (uint32_t ) (c & 0xff); } return hash;}/* * Hash callback functions. */static uint32_t dict_attr_name_hash(const void *data){ return dict_hashname(((const DICT_ATTR *)data)->name);}static int dict_attr_name_cmp(const void *one, const void *two){ const DICT_ATTR *a = one; const DICT_ATTR *b = two; return strcasecmp(a->name, b->name);}static uint32_t dict_attr_value_hash(const void *data){ uint32_t hash; const DICT_ATTR *attr = data; hash = fr_hash(&attr->vendor, sizeof(attr->vendor)); return fr_hash_update(&attr->attr, sizeof(attr->attr), hash);}static int dict_attr_value_cmp(const void *one, const void *two){ const DICT_ATTR *a = one; const DICT_ATTR *b = two; if (a->vendor < b->vendor) return -1; if (a->vendor > b->vendor) return +1; return a->attr - b->attr;}static uint32_t dict_vendor_name_hash(const void *data){ return dict_hashname(((const DICT_VENDOR *)data)->name);}static int dict_vendor_name_cmp(const void *one, const void *two){ const DICT_VENDOR *a = one; const DICT_VENDOR *b = two; return strcasecmp(a->name, b->name);}static uint32_t dict_vendor_value_hash(const void *data){ return fr_hash(&(((const DICT_VENDOR *)data)->vendorpec), sizeof(((const DICT_VENDOR *)data)->vendorpec));}static int dict_vendor_value_cmp(const void *one, const void *two){ const DICT_VENDOR *a = one; const DICT_VENDOR *b = two; return a->vendorpec - b->vendorpec;}static uint32_t dict_value_name_hash(const void *data){ uint32_t hash; const DICT_VALUE *dval = data; hash = dict_hashname(dval->name); return fr_hash_update(&dval->attr, sizeof(dval->attr), hash);}static int dict_value_name_cmp(const void *one, const void *two){ int rcode; const DICT_VALUE *a = one; const DICT_VALUE *b = two; rcode = a->attr - b->attr; if (rcode != 0) return rcode; return strcasecmp(a->name, b->name);}static uint32_t dict_value_value_hash(const void *data){ uint32_t hash; const DICT_VALUE *dval = data; hash = fr_hash(&dval->attr, sizeof(dval->attr)); return fr_hash_update(&dval->value, sizeof(dval->value), hash);}static int dict_value_value_cmp(const void *one, const void *two){ int rcode; const DICT_VALUE *a = one; const DICT_VALUE *b = two; rcode = a->attr - b->attr; if (rcode != 0) return rcode; return a->value - b->value;}/* * Free the list of stat buffers */static void dict_stat_free(void){ dict_stat_t *this, *next; free(stat_root_dir); stat_root_dir = NULL; free(stat_root_file); stat_root_file = NULL; if (!stat_head) { stat_tail = NULL; return; } for (this = stat_head; this != NULL; this = next) { next = this->next; free(this->name); free(this); } stat_head = stat_tail = NULL;}/* * Add an entry to the list of stat buffers. */static void dict_stat_add(const char *name, const struct stat *stat_buf){ dict_stat_t *this; this = malloc(sizeof(*this)); if (!this) return; memset(this, 0, sizeof(*this)); this->name = strdup(name); this->mtime = stat_buf->st_mtime; if (!stat_head) { stat_head = stat_tail = this; } else { stat_tail->next = this; stat_tail = this; }}/* * See if any dictionaries have changed. If not, don't * do anything. */static int dict_stat_check(const char *root_dir, const char *root_file){ struct stat buf; dict_stat_t *this; if (!stat_root_dir) return 0; if (!stat_root_file) return 0; if (strcmp(root_dir, stat_root_dir) != 0) return 0; if (strcmp(root_file, stat_root_file) != 0) return 0; if (!stat_head) return 0; /* changed, reload */ for (this = stat_head; this != NULL; this = this->next) { if (stat(this->name, &buf) < 0) return 0; if (buf.st_mtime != this->mtime) return 0; } return 1;}typedef struct fr_pool_t { void *page_end; void *free_ptr; struct fr_pool_t *page_free; struct fr_pool_t *page_next;} fr_pool_t;#define FR_POOL_SIZE (32768)#define FR_ALLOC_ALIGN (8)static fr_pool_t *dict_pool = NULL;static fr_pool_t *fr_pool_create(void){ fr_pool_t *fp = malloc(FR_POOL_SIZE); if (!fp) return NULL; fp->page_end = ((uint8_t *) fp) + FR_POOL_SIZE; fp->free_ptr = ((uint8_t *) fp) + sizeof(*fp); fp->page_free = fp; fp->page_next = NULL; return fp;}static void fr_pool_delete(fr_pool_t **pfp){ fr_pool_t *fp, *next; if (!pfp || !*pfp) return; for (fp = *pfp; fp != NULL; fp = next) { next = fp->page_next; free(fp); }}static void *fr_pool_alloc(size_t size){ void *ptr; if (size == 0) return NULL; if (size > 256) return NULL; /* shouldn't happen */ if (!dict_pool) { dict_pool = fr_pool_create(); if (!dict_pool) return NULL; } if ((size & (FR_ALLOC_ALIGN - 1)) != 0) { size += FR_ALLOC_ALIGN - (size & (FR_ALLOC_ALIGN - 1)); } if ((((uint8_t *) dict_pool->page_free->free_ptr) + size) > (uint8_t *) dict_pool->page_free->page_end) { dict_pool->page_free->page_next = fr_pool_create(); if (!dict_pool->page_free->page_next) return NULL; dict_pool->page_free = dict_pool->page_free->page_next; } ptr = dict_pool->page_free->free_ptr; dict_pool->page_free->free_ptr = ((uint8_t *) dict_pool->page_free->free_ptr) + size; return ptr;}static void fr_pool_free(UNUSED void *ptr){ /* * Place-holder for later code. */}/* * Free the dictionary_attributes and dictionary_values lists. */void dict_free(void){ /* * Free the tables */ fr_hash_table_free(vendors_byname); fr_hash_table_free(vendors_byvalue); vendors_byname = NULL; vendors_byvalue = NULL; fr_hash_table_free(attributes_byname); fr_hash_table_free(attributes_byvalue); attributes_byname = NULL; attributes_byvalue = NULL; fr_hash_table_free(values_byname); fr_hash_table_free(values_byvalue); values_byname = NULL; values_byvalue = NULL; memset(dict_base_attrs, 0, sizeof(dict_base_attrs)); fr_pool_delete(&dict_pool); dict_stat_free();}/* * Add vendor to the list. */int dict_addvendor(const char *name, int value){ size_t length; DICT_VENDOR *dv; if (value >= 32767) { librad_log("dict_addvendor: Cannot handle vendor ID larger than 65535"); return -1; } if ((length = strlen(name)) >= DICT_VENDOR_MAX_NAME_LEN) { librad_log("dict_addvendor: vendor name too long"); return -1; } if ((dv = fr_pool_alloc(sizeof(*dv) + length)) == NULL) { librad_log("dict_addvendor: out of memory"); return -1; } strcpy(dv->name, name); dv->vendorpec = value; dv->type = dv->length = 1; /* defaults */ if (!fr_hash_table_insert(vendors_byname, dv)) { DICT_VENDOR *old_dv; old_dv = fr_hash_table_finddata(vendors_byname, dv); if (!old_dv) { librad_log("dict_addvendor: Failed inserting vendor name %s", name); return -1; } if (old_dv->vendorpec != dv->vendorpec) { librad_log("dict_addvendor: Duplicate vendor name %s", name); return -1; } /* * Already inserted. Discard the duplicate entry. */ fr_pool_free(dv); return 0; } /* * Insert the SAME pointer (not free'd when this table is * deleted), into another table. * * We want this behaviour because we want OLD names for * the attributes to be read from the configuration * files, but when we're printing them, (and looking up * by value) we want to use the NEW name. */ if (!fr_hash_table_replace(vendors_byvalue, dv)) { librad_log("dict_addvendor: Failed inserting vendor %s", name); return -1; } return 0;}/* * Add an attribute to the dictionary. */int dict_addattr(const char *name, int vendor, int type, int value, ATTR_FLAGS flags){ static int max_attr = 0; DICT_ATTR *attr; if (strlen(name) > (sizeof(attr->name) -1)) { librad_log("dict_addattr: attribute name too long"); return -1; } /* * If the value is '-1', that means use a pre-existing * one (if it already exists). If one does NOT already exist, * then create a new attribute, with a non-conflicting value, * and use that. */ if (value == -1) { if (dict_attrbyname(name)) { return 0; /* exists, don't add it again */ } value = ++max_attr; } else if (vendor == 0) { /* * Update 'max_attr' */ if (value > max_attr) { max_attr = value; } } if (value < 0) { librad_log("dict_addattr: ATTRIBUTE has invalid number (less than zero)"); return -1; } if (value >= 65536) { librad_log("dict_addattr: ATTRIBUTE has invalid number (larger than 65535)."); return -1; } if (vendor) { DICT_VENDOR *dv; static DICT_VENDOR *last_vendor = NULL; /* * Most ATTRIBUTEs are bunched together by * VENDOR. We can save a lot of lookups on * dictionary initialization by caching the last * vendor. */ if (last_vendor && (vendor == last_vendor->vendorpec)) { dv = last_vendor; } else { dv = dict_vendorbyvalue(vendor); last_vendor = dv; } /* * If the vendor isn't defined, die. */ if (!dv) { librad_log("dict_addattr: Unknown vendor"); return -1; } /* * FIXME: Switch over dv->type, and limit things * properly. */ if ((dv->type == 1) && (value >= 256)) { librad_log("dict_addattr: ATTRIBUTE has invalid number (larger than 255)."); return -1; } /* else 256..65535 are allowed */ } /* * Create a new attribute for the list */ if ((attr = fr_pool_alloc(sizeof(*attr))) == NULL) { librad_log("dict_addattr: out of memory"); return -1; } strcpy(attr->name, name); attr->attr = value; attr->attr |= (vendor << 16); /* FIXME: hack */ attr->vendor = vendor; attr->type = type; attr->flags = flags; attr->vendor = vendor; /* * Insert the attribute, only if it's not a duplicate. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -