mirror of
				https://github.com/ossrs/srs.git
				synced 2025-03-09 15:49:59 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			190 lines
		
	
	
	
		
			4.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			190 lines
		
	
	
	
		
			4.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include "stx.h"
 | |
| #include "common.h"
 | |
| 
 | |
| 
 | |
| /*****************************************
 | |
|  * Basic types definitions
 | |
|  */
 | |
| 
 | |
| typedef struct _stx_dns_data {
 | |
|     struct in_addr *addrs;
 | |
|     int num_addrs;
 | |
|     int cur;
 | |
|     time_t expires;
 | |
| } stx_dns_data_t;
 | |
| 
 | |
| 
 | |
| #define MAX_HOST_ADDRS 1024
 | |
| 
 | |
| static struct in_addr addr_list[MAX_HOST_ADDRS];
 | |
| 
 | |
| stx_cache_t *_stx_dns_cache = NULL;
 | |
| 
 | |
| extern int _stx_dns_ttl;
 | |
| extern int _stx_dns_getaddrlist(const char *hostname, struct in_addr *addrs,
 | |
| 				int *num_addrs, st_utime_t timeout);
 | |
| 
 | |
| 
 | |
| static unsigned long hash_hostname(const void *key)
 | |
| {
 | |
|     const char *name = (const char *)key;
 | |
|     unsigned long hash = 0;
 | |
| 
 | |
|     while (*name)
 | |
| 	hash = (hash << 4) - hash + *name++; /* hash = hash * 15 + *name++ */
 | |
| 
 | |
|     return hash;
 | |
| }
 | |
| 
 | |
| static void cleanup_entry(void *key, void *data)
 | |
| {
 | |
|     if (key)
 | |
| 	free(key);
 | |
| 
 | |
|     if (data) {
 | |
| 	if (((stx_dns_data_t *)data)->addrs)
 | |
| 	    free(((stx_dns_data_t *)data)->addrs);
 | |
| 	free(data);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static int lookup_entry(const char *host, struct in_addr *addrs,
 | |
| 			int *num_addrs, int rotate)
 | |
| {
 | |
|     stx_cache_entry_t *entry;
 | |
|     stx_dns_data_t *data;
 | |
|     int n;
 | |
| 
 | |
|     entry = stx_cache_entry_lookup(_stx_dns_cache, host);
 | |
|     if (entry) {
 | |
| 	data = (stx_dns_data_t *)stx_cache_entry_getdata(entry);
 | |
| 	if (st_time() <= data->expires) {
 | |
| 	    if (*num_addrs == 1) {
 | |
| 		if (rotate) {
 | |
| 		    *addrs = data->addrs[data->cur++];
 | |
| 		    if (data->cur >= data->num_addrs)
 | |
| 			data->cur = 0;
 | |
| 		} else {
 | |
| 		    *addrs = data->addrs[0];
 | |
| 		}
 | |
| 	    } else {
 | |
| 		n = STX_MIN(*num_addrs, data->num_addrs);
 | |
| 		memcpy(addrs, data->addrs, n * sizeof(*addrs));
 | |
| 		*num_addrs = n;
 | |
| 	    }
 | |
| 
 | |
| 	    stx_cache_entry_release(_stx_dns_cache, entry);
 | |
| 	    return 1;
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * Cache entry expired: decrement its refcount and purge it from cache.
 | |
| 	 */
 | |
| 	stx_cache_entry_release(_stx_dns_cache, entry);
 | |
| 	stx_cache_entry_delete(_stx_dns_cache, entry);
 | |
|     }
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static void insert_entry(const char *host, struct in_addr *addrs, int count)
 | |
| {
 | |
|     stx_cache_entry_t *entry;
 | |
|     stx_dns_data_t *data;
 | |
|     char *key;
 | |
|     size_t n;
 | |
| 
 | |
|     if (_stx_dns_ttl > 0) {
 | |
| 	key = strdup(host);
 | |
| 	data = (stx_dns_data_t *)malloc(sizeof(stx_dns_data_t));
 | |
| 	n = count * sizeof(*addrs);
 | |
| 	if (data) {
 | |
| 	    data->addrs = (struct in_addr *)malloc(n);
 | |
| 	    if (data->addrs)
 | |
| 		memcpy(data->addrs, addrs, n);
 | |
| 	    data->num_addrs = count;
 | |
| 	    data->cur = 0;
 | |
| 	    data->expires = st_time() + _stx_dns_ttl;
 | |
| 	}
 | |
| 	entry = stx_cache_entry_create(key, data, strlen(host) + 1 +
 | |
| 				       sizeof(stx_dns_data_t) + n +
 | |
| 				       stx_cache_entry_sizeof());
 | |
| 	if (key && data && data->addrs && entry &&
 | |
| 	    stx_cache_entry_insert(_stx_dns_cache, entry) == 0) {
 | |
| 	    stx_cache_entry_release(_stx_dns_cache, entry);
 | |
| 	    return;
 | |
| 	}
 | |
| 
 | |
| 	if (entry)
 | |
| 	    stx_cache_entry_delete(_stx_dns_cache, entry);
 | |
| 	else
 | |
| 	    cleanup_entry(key, data);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| int _stx_dns_cache_getaddrlist(const char *hostname, struct in_addr *addrs,
 | |
| 			       int *num_addrs, st_utime_t timeout,
 | |
| 			       int rotate)
 | |
| {
 | |
|     char host[128];
 | |
|     int n, count;
 | |
| 
 | |
|     if (!_stx_dns_cache)
 | |
| 	return _stx_dns_getaddrlist(hostname, addrs, num_addrs, timeout);
 | |
| 
 | |
|     for (n = 0; n < sizeof(host) - 1 && hostname[n]; n++) {
 | |
| 	host[n] = tolower(hostname[n]);
 | |
|     }
 | |
|     host[n] = '\0';
 | |
| 
 | |
|     if (lookup_entry(host, addrs, num_addrs, rotate))
 | |
| 	return 0;
 | |
| 
 | |
|     count = MAX_HOST_ADDRS;
 | |
|     if (_stx_dns_getaddrlist(host, addr_list, &count, timeout) < 0)
 | |
| 	return -1;
 | |
|     n = STX_MIN(*num_addrs, count);
 | |
|     memcpy(addrs, addr_list, n * sizeof(*addrs));
 | |
|     *num_addrs = n;
 | |
| 
 | |
|     insert_entry(host, addr_list, count);
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| int stx_dns_cache_init(size_t max_size, size_t max_bytes, size_t hash_size)
 | |
| {
 | |
|     _stx_dns_cache = stx_cache_create(max_size, max_bytes, hash_size,
 | |
| 				  hash_hostname,
 | |
| 				  (long (*)(const void *, const void *))strcmp,
 | |
| 				  cleanup_entry);
 | |
|     if (!_stx_dns_cache)
 | |
| 	return -1;
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| void stx_dns_cache_getinfo(stx_cache_info_t *info)
 | |
| {
 | |
|     if (_stx_dns_cache)
 | |
| 	stx_cache_getinfo(_stx_dns_cache, info);
 | |
|     else
 | |
| 	memset(info, 0, sizeof(stx_cache_info_t));
 | |
| }	
 | |
| 
 | |
| int stx_dns_getaddrlist(const char *hostname, struct in_addr *addrs,
 | |
| 			int *num_addrs, st_utime_t timeout)
 | |
| {
 | |
|     return _stx_dns_cache_getaddrlist(hostname, addrs, num_addrs, timeout, 0);
 | |
| }
 | |
| 
 | |
| int stx_dns_getaddr(const char *hostname, struct in_addr *addr,
 | |
| 		    st_utime_t timeout)
 | |
| {
 | |
|     int n = 1;
 | |
| 
 | |
|     return _stx_dns_cache_getaddrlist(hostname, addr, &n, timeout, 1);
 | |
| }
 | |
| 
 |