⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jid.c

📁 jabber server jabber server jabber server jabber server
💻 C
📖 第 1 页 / 共 2 页
字号:
/* -------------------------------------------------------------------------- * * License * * The contents of this file are subject to the Jabber Open Source License * Version 1.0 (the "JOSL").  You may not copy or use this file, in either * source code or executable form, except in compliance with the JOSL. You * may obtain a copy of the JOSL at http://www.jabber.org/ or at * http://www.opensource.org/.   * * Software distributed under the JOSL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the JOSL * for the specific language governing rights and limitations under the * JOSL. * * Copyrights *  * Portions created by or assigned to Jabber.com, Inc. are  * Copyright (c) 1999-2002 Jabber.com, Inc.  All Rights Reserved.  Contact * information for Jabber.com, Inc. is available at http://www.jabber.com/. * * Portions Copyright (c) 1998-1999 Jeremie Miller. *  * Acknowledgements *  * Special thanks to the Jabber Open Source Contributors for their * suggestions and support of Jabber. *  * Alternatively, the contents of this file may be used under the terms of the * GNU General Public License Version 2 or later (the "GPL"), in which case * the provisions of the GPL are applicable instead of those above.  If you * wish to allow use of your version of this file only under the terms of the * GPL and not to allow others to use your version of this file under the JOSL, * indicate your decision by deleting the provisions above and replace them * with the notice and other provisions required by the GPL.  If you do not * delete the provisions above, a recipient may use your version of this file * under either the JOSL or the GPL.  *  * --------------------------------------------------------------------------*//** * @file jid.c * @brief representation and normalization of JabberIDs */#include <jabberdlib.h>#ifdef LIBIDN#  include <stringprep.h>/** * @brief datastructure to build the stringprep caches */typedef struct _jid_prep_entry_st {    char *preped;	/**< the result of the preparation, NULL if unchanged */    time_t last_used;	/**< when this result has last been successfully used */    unsigned int used_count; /**< how often this result has been successfully used */    int size;		/**< the min buffer size needed to hold the result (strlen+1) */} *_jid_prep_entry_t;/** * @brief string preparation cache */typedef struct _jid_prep_cache_st {    xht hashtable;	/**< the hash table containing the preped strings */    pth_mutex_t mutex;	/**< mutex controling the access to the hashtable */    const Stringprep_profile *profile;    			/**< the stringprep profile used for this cache */} *_jid_prep_cache_t;/** * stringprep cache containging already preped nodes * * we are using global caches here for two reasons: * - I do not see why different instances would want *   to have different caches as we are always doing *   the same * - For per instance caches I would have to modify the *   interface of the jid_*() functions which would break *   compatibility with transports */_jid_prep_cache_t _jid_prep_cache_node = NULL;/** * stringprep cache containing already preped domains */_jid_prep_cache_t _jid_prep_cache_domain = NULL;/** * stringprep cache containing already preped resources */_jid_prep_cache_t _jid_prep_cache_resource = NULL;/** * walker for cleaning up stringprep caches * * @param h the hash we are walking through * @param key the key of this item * @param val the value of this item * @param arg delete entries older as this unix timestamp */void _jid_clean_walker(xht h, const char *key, void *val, void *arg) {    time_t *keep_newer_as = (time_t*)arg;    _jid_prep_entry_t entry = (_jid_prep_entry_t)val;    if (entry == NULL)	return;    if (entry->last_used <= *keep_newer_as) {	xhash_zap(h, key);	if (entry->preped != NULL)	    free(entry->preped);	free(entry);	/* sorry, I have to cast the const away */	/* any idea how I could delete the key else? */	if (key != NULL)	    free((void*)key);    }}/** * walk through a single stringprep cache and check which entries have expired */void _jid_clean_single_cache(_jid_prep_cache_t cache, time_t keep_newer_as) {    /* acquire the lock on the cache */    pth_mutex_acquire(&(cache->mutex), FALSE, NULL);    /* walk over all entries */    xhash_walk(cache->hashtable, _jid_clean_walker, (void*)&keep_newer_as);    /* we're done, release the lock on the cache */    pth_mutex_release(&(cache->mutex));}/** * walk through the stringprep caches and check which entries have expired */void jid_clean_cache() {    /* XXX make this configurable? */    time_t keep_newer_as = time(NULL) - 900;    /* cleanup the nodeprep cache */    _jid_clean_single_cache(_jid_prep_cache_node, keep_newer_as);        /* cleanup the domain preparation cache */    _jid_clean_single_cache(_jid_prep_cache_domain, keep_newer_as);        /* cleanup the resourceprep cache */    _jid_clean_single_cache(_jid_prep_cache_resource, keep_newer_as);}/** * caching wrapper around a stringprep function * * @param in_out_buffer buffer containing what has to be stringpreped and that gets the result * @param max_len size of the buffer * @param cache the used cache, defining also the used stringprep profile * @return the return code of the stringprep call */int _jid_cached_stringprep(char *in_out_buffer, int max_len, _jid_prep_cache_t cache) {    _jid_prep_entry_t preped;    int result = STRINGPREP_OK;    /* check that the cache already exists     * we can not do anything as we don't know which profile has to be used */    if (cache == NULL) {	return STRINGPREP_UNKNOWN_PROFILE;    }    /* is there something that has to be stringpreped? */    if (in_out_buffer == NULL) {	return STRINGPREP_OK;    }    /* acquire the lock on the cache */    pth_mutex_acquire(&(cache->mutex), FALSE, NULL);    /* check if the requested preparation has already been done */    preped = (_jid_prep_entry_t)xhash_get(cache->hashtable, in_out_buffer);    if (preped != NULL) {	/* we already prepared this argument */	if (preped->size <= max_len) {	    /* we can use the result */	    /* update the statistic */	    preped->used_count++;	    preped->last_used = time(NULL);	    /* do we need to copy the result? */	    if (preped->preped != NULL) {		/* copy the result */		strcpy(in_out_buffer, preped->preped);	    }	    result = STRINGPREP_OK;	} else {	    /* we need a bigger buffer */	    result = STRINGPREP_TOO_SMALL_BUFFER;	}		/* we're done, release the lock on the cache */	pth_mutex_release(&(cache->mutex));    } else {	char *original;	/* stringprep needs time, release the lock on the cache for the meantime */	pth_mutex_release(&(cache->mutex));	/* we have to keep the key */	original = strdup(in_out_buffer);		/* try to prepare the string */	result = stringprep(in_out_buffer, max_len, STRINGPREP_NO_UNASSIGNED, cache->profile);	/* did we manage to prepare the string? */	if (result == STRINGPREP_OK && original != NULL) {	    /* generate an entry for the cache */	    preped = (_jid_prep_entry_t)malloc(sizeof(struct _jid_prep_entry_st));	    if (preped != NULL) {		/* has there been modified something? */		if (j_strcmp(in_out_buffer, original) == 0) {		    /* no, we don't need to store a copy of the original string */		    preped->preped = NULL;		} else {		    /* yes, store the stringpreped string */		    preped->preped = strdup(in_out_buffer);		}		preped->last_used = time(NULL);		preped->used_count = 1;		preped->size = strlen(in_out_buffer)+1;		/* acquire the lock on the cache again */		pth_mutex_acquire(&(cache->mutex), FALSE, NULL);		/* store the entry in the cache */		xhash_put(cache->hashtable, original, preped);		/* we're done, release the lock on the cache */		pth_mutex_release(&(cache->mutex));	    } else {		/* we don't need the copy of the key, if there is no memory to store it */		free(original);	    }	} else {	    /* we don't need the copy of the original value */	    if (original != NULL)		free(original);	}    }    return result;}/** * free a single stringprep cache * * @param cache the cache to free */void _jid_stop_single_cache(_jid_prep_cache_t *cache) {    if (*cache == NULL)	return;    _jid_clean_single_cache(*cache, time(NULL));        pth_mutex_acquire(&((*cache)->mutex), FALSE, NULL);    xhash_free((*cache)->hashtable);    free(*cache);    *cache = NULL;}/** * init a single stringprep cache * * @param cache the cache to init * @param prime the prime used to init the hashtable * @param profile profile used to prepare the strings */void _jid_init_single_cache(_jid_prep_cache_t *cache, int prime, const Stringprep_profile *profile) {    /* do not init a cache twice */    if (*cache == NULL) {	*cache = (_jid_prep_cache_t)malloc(sizeof(struct _jid_prep_cache_st));	pth_mutex_init(&((*cache)->mutex));	(*cache)->hashtable = xhash_new(prime);	(*cache)->profile = profile;    }}/** * free the stringprep caches */void jid_stop_caching() {    _jid_stop_single_cache(&_jid_prep_cache_node);    _jid_stop_single_cache(&_jid_prep_cache_domain);    _jid_stop_single_cache(&_jid_prep_cache_resource);}/** * init the stringprep caches * (do not call this twice at the same time, we do not have the mutexes yet) */void jid_init_cache() {    /* init the nodeprep cache */    _jid_init_single_cache(&_jid_prep_cache_node, 2003, stringprep_xmpp_nodeprep);    /* init the nameprep cache (domains) */    _jid_init_single_cache(&_jid_prep_cache_domain, 2003, stringprep_nameprep);    /* init the resourceprep cache */    _jid_init_single_cache(&_jid_prep_cache_resource, 2003, stringprep_xmpp_resourceprep);}/** * nameprep the domain identifier in a JID and check if it is valid * * @param jid data structure holding the JID * @return 0 if JID is valid, non zero otherwise */int _jid_safe_domain(jid id) {    int result=0;    /* there must be a domain identifier */    if (j_strlen(id->server) == 0)	return 1;    /* nameprep the domain identifier */    result = _jid_cached_stringprep(id->server, strlen(id->server)+1, _jid_prep_cache_domain);    if (result == STRINGPREP_TOO_SMALL_BUFFER) {	/* nameprep wants to expand the string, e.g. conversion from &szlig; to ss */	size_t biggerbuffersize = 1024;	char *biggerbuffer = pmalloc(id->p, biggerbuffersize);	if (biggerbuffer == NULL)	    return 1;	strcpy(biggerbuffer, id->server);	result = _jid_cached_stringprep(biggerbuffer, biggerbuffersize, _jid_prep_cache_domain);	id->server = biggerbuffer;    }    if (result != STRINGPREP_OK)	return 1;    /* the namepreped domain must not be longer than 1023 bytes */    if (j_strlen(id->server) > 1023)	return 1;    /* if nothing failed, the domain is valid */    return 0;}/** * nodeprep the node identifier in a JID and check if it is valid * * @param jid data structure holding the JID * @return 0 if JID is valid, non zero otherwise */int _jid_safe_node(jid id) {    int result=0;    /* it is valid to have no node identifier in the JID */    if (id->user == NULL)	return 0;    /* nodeprep */    result = _jid_cached_stringprep(id->user, strlen(id->user)+1, _jid_prep_cache_node);    if (result == STRINGPREP_TOO_SMALL_BUFFER) {	/* nodeprep wants to expand the string, e.g. conversion from &szlig; to ss */	size_t biggerbuffersize = 1024;	char *biggerbuffer = pmalloc(id->p, biggerbuffersize);	if (biggerbuffer == NULL)	    return 1;	strcpy(biggerbuffer, id->user);	result = _jid_cached_stringprep(biggerbuffer, biggerbuffersize, _jid_prep_cache_node);	id->user = biggerbuffer;    }    if (result != STRINGPREP_OK)	return 1;    /* the nodepreped node must not be longer than 1023 bytes */    if (j_strlen(id->user) > 1023)	return 1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -