Create your Gitee Account
Explore and code with more than 12 million developers,Free private repositories !:)
Sign up
文件
Clone or Download
sbparsehost.c 9.17 KB
Copy Edit Raw Blame History
calvin authored 2015-06-04 19:54 . a
#include <ares.h>
#include <sys/types.h>
#include <string.h>
#include <arpa/nameser.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "sblist.h"
#include "sbparsehost.h"
#include "sbalance.h"
#define SB_DNS_HASH_SLOTS 111
#define SB_DNS_TIMEOUT_TIME 2500 /* 5000ms */
#define SB_DNS_ARES_OPT ARES_OPT_TIMEOUTMS|ARES_OPT_TRIES
static struct hlist_head *hash_slots;
static struct list_head *wait_parse_list_head;
static struct list_head *parsing_list_head;
struct ares_options options;
static void callback_gethost(void *arg, int status, int timeouts, struct hostent *h);
static unsigned long RSHash(const char *str)
{
unsigned long a = 63689;
unsigned long b = 378551;
unsigned long hash = 0;
while(*str) {
hash = hash * a + (*str++);
a *= b;
}
return hash;
}
int sb_dns_init_env()
{
int i = 0;
hash_slots = (struct hlist_head*)(malloc( sizeof(struct hlist_head) * SB_DNS_HASH_SLOTS ));
if (hash_slots == NULL)
return SB_ERROR;
for (i = 0; i < SB_DNS_HASH_SLOTS; i++) {
INIT_HLIST_HEAD(&hash_slots[i]);
}
wait_parse_list_head = (struct list_head*)(malloc(sizeof(struct list_head)));
if (wait_parse_list_head == NULL) {
free(hash_slots);
return SB_ERROR;
}
INIT_LIST_HEAD(wait_parse_list_head);
parsing_list_head = (struct list_head*)(malloc(sizeof(struct list_head)));
if (wait_parse_list_head == NULL) {
free(hash_slots);
free(wait_parse_list_head);
return SB_ERROR;
}
INIT_LIST_HEAD(parsing_list_head);
options.timeout = SB_DNS_TIMEOUT_TIME;
options.tries = 2;
return SB_OK;
}
/* @RETURN 1. SB_NOTFOUND 2. SB_OK */
int sb_dns_modify_status(char *host, int new_status)
{
int slot_index;
struct hlist_head *hash_head;
slot_index = RSHash(host) % SB_DNS_HASH_SLOTS;
hash_head = &hash_slots[slot_index];
if (hash_head->first == NULL)
return SB_NOTFOUND;
else {
struct hlist_node *pos;
struct hlist_node *pre_pos = NULL;
struct sb_dns *type;
int cmp;
hlist_for_each_entry(type, pos, hash_head, hash_node) {
if ((cmp = strcmp(type->host, host)) == 0) {
type->status = new_status;
return SB_OK;
} else if (cmp > 0) {
return SB_NOTFOUND;
}
}
return SB_NOTFOUND;
}
}
void sb_dns_remove_session(struct sb_session *sess)
{
if (sess->dns_list_node.next != &sess->dns_list_node) {
list_del_init(&sess->dns_list_node);
}
}
/* @RETURN
1. SB_OK(find host's ip)
2. SB_AGAIN(a. not find host's ip, but add query request, b. find host, but the status is parsing)
3. SB_TIMEOUT(find host, but status is timeout) temp status, not possible status
4. SB_ERROR
*/
int sb_dns_query_host_ip(const char *host, struct sb_session *sess)
{
int rc;
struct sb_dns *new_sb_dns;
unsigned long hash_val;
int slot_index;
struct hlist_head *hash_head;
int flag = 0;
char *ip;
int len;
int i =0;
slot_index = RSHash(host) % SB_DNS_HASH_SLOTS;
hash_head = &hash_slots[slot_index];
ip = sess->server.net_address.ip;
len = sizeof(sess->server.net_address.ip);
if (hash_head->first == NULL) {
new_sb_dns = (struct sb_dns*)calloc(1, sizeof(struct sb_dns));
if (!new_sb_dns) {
return SB_ERROR;
}
/* new_sb_dns->timeout_time = sb_get_msec_timeout_time(SB_DNS_TIMEOUT); */
INIT_LIST_HEAD(&new_sb_dns->waiting_session_list);
list_add(&sess->dns_list_node, &new_sb_dns->waiting_session_list);
sess->dns = new_sb_dns;
strcpy(new_sb_dns->host, host);
rc = ares_init_options(&new_sb_dns->channel, &options, SB_DNS_ARES_OPT);
if (rc) {
return SB_ERROR;
}
ares_gethostbyname(new_sb_dns->channel, new_sb_dns->host, AF_INET,callback_gethost, new_sb_dns);
/* add to hash and wait list */
hlist_add_head(&new_sb_dns->hash_node, hash_head);
new_sb_dns->status = SB_DNS_STATUS_WAITING;
list_add(&new_sb_dns->list_node, wait_parse_list_head);
return SB_AGAIN;
}
else {
struct hlist_node *pos = NULL;
struct hlist_node *pre_pos = NULL;
struct sb_dns *type;
int cmp;
int ip_len;
hlist_for_each_entry(type, pos, hash_head, hash_node) {
if ((cmp = strcmp(type->host, host)) == 0) {
sess->dns = (struct sb_dns*)type;
if (type->status == SB_DNS_STATUS_OK) {
if ((ip_len = strlen(type->ip)) > len) {
return SB_ERROR;
} else {
memcpy(ip, type->ip, ip_len);
ip[ip_len] = '\0';
return SB_OK;
}
} else if (type->status == SB_DNS_STATUS_WAITING || type->status == SB_DNS_STATUS_PARSING) {
/* add the session to the waiting list for this dns request */
list_add(&sess->dns_list_node, &type->waiting_session_list);
return SB_AGAIN;
} else if (type->status == SB_DNS_STATUS_DESTORYED) {
list_add(&sess->dns_list_node, &type->waiting_session_list);
/* re-add to wait parsing list to request a parse */
rc = ares_init_options(&type->channel, &options, SB_DNS_ARES_OPT);
if (rc)
return SB_ERROR;
type->status = SB_DNS_STATUS_WAITING;
list_add(&type->list_node, wait_parse_list_head);
return SB_AGAIN;
} else {
FatalOutput("not possible status for sb_dns, bug need fix");
return SB_ERROR;
}
} else if (cmp > 0) {
new_sb_dns = (struct sb_dns*)calloc(1, sizeof(struct sb_dns));
if (!new_sb_dns)
return SB_ERROR;
INIT_LIST_HEAD(&new_sb_dns->waiting_session_list);
list_add(&sess->dns_list_node, &new_sb_dns->waiting_session_list);
sess->dns = new_sb_dns;
strcpy(new_sb_dns->host, host);
rc = ares_init_options(&new_sb_dns->channel, &options, SB_DNS_ARES_OPT);
if (rc)
return SB_ERROR;
ares_gethostbyname(new_sb_dns->channel, new_sb_dns->host, AF_INET,callback_gethost, new_sb_dns);
/* new_sb_dns->timeout_time = sb_get_msec_timeout_time(SB_DNS_TIMEOUT); */
hlist_add_before(&new_sb_dns->hash_node, pos);
new_sb_dns->status = SB_DNS_STATUS_WAITING;
list_add(&new_sb_dns->list_node, wait_parse_list_head);
return SB_AGAIN;
} else {
pre_pos = pos;
}
}
new_sb_dns = (struct sb_dns*)calloc(1, sizeof(struct sb_dns));
if (!new_sb_dns)
return SB_ERROR;
INIT_LIST_HEAD(&new_sb_dns->waiting_session_list);
list_add(&sess->dns_list_node, &new_sb_dns->waiting_session_list);
sess->dns = new_sb_dns;
strcpy(new_sb_dns->host, host);
rc = ares_init_options(&new_sb_dns->channel, &options, SB_DNS_ARES_OPT);
if (rc)
return SB_ERROR;
ares_gethostbyname(new_sb_dns->channel, new_sb_dns->host, AF_INET, callback_gethost, new_sb_dns);
/* new_sb_dns->timeout_time = sb_get_msec_timeout_time(SB_DNS_TIMEOUT); */
hlist_add_after(pre_pos, &new_sb_dns->hash_node);
new_sb_dns->status = SB_DNS_STATUS_WAITING;
list_add(&new_sb_dns->list_node, wait_parse_list_head);
return SB_AGAIN;
}
}
int sb_dns_reparse_host(struct sb_dns *dns, struct sb_session *sess)
{
int rc;
if (ares_init_options(&dns->channel, &options, SB_DNS_ARES_OPT)) {
return SB_ERROR;
}
dns->status = SB_DNS_STATUS_WAITING;
list_add(&dns->list_node, wait_parse_list_head);
list_add(&sess->dns_list_node, &dns->waiting_session_list);
return SB_OK;
}
static void callback_gethost(void *arg, int status, int timeouts, struct hostent *h)
{
struct sb_dns *dns;
char** pptr;
dns = (struct sb_dns*)arg;
if (h == NULL) {
if (status == ARES_ETIMEOUT)
dns->status = SB_DNS_STATUS_TIMEOUT;
else
dns->status = SB_DNS_STATUS_ERROR;
} else {
dns->status = SB_DNS_STATUS_OK;
for (pptr = h->h_addr_list; *pptr != NULL; pptr++) {
/* if (inet_ntop(h->h_addrtype, *pptr, dns->ip, sizeof(dns->ip) - 1)) */
if (inet_ntop(AF_INET, *pptr, dns->ip, sizeof(dns->ip) - 1)) { /* just use ipv4 */
return;
}
}
FatalOutput("inet_ntop not right %s", *pptr);
}
}
/* @RETURN 1. SB_ERROR 2. SB_OK */
int
sb_dns_process (struct sb_cycle_env *env)
{
fd_set readers, writers;
int nfds = 1;
FD_ZERO (&readers);
FD_ZERO (&writers);
int count;
struct sb_dns *pos, *n;
struct sb_session *sess_pos, *sess_n;
struct timeval maxtv = { 0, 500 }; /* 50ms */
int rc;
list_for_each_entry (pos, parsing_list_head, list_node)
{
nfds = ares_fds (pos->channel, &readers, &writers);
}
count = select (nfds, &readers, &writers, NULL, &maxtv);
if (count == -1)
{
return SB_ERROR;
}
list_for_each_entry_safe (pos, n, parsing_list_head, list_node)
{
ares_process (pos->channel, &readers, &writers);
if (pos->status != SB_DNS_STATUS_PARSING)
{
list_del_init (&pos->list_node);
/* do session's done callback */
list_for_each_entry_safe (sess_pos, sess_n,
&pos->waiting_session_list, dns_list_node)
{
sess_pos->sb_dns_request_done (env, sess_pos);
list_del_init (&sess_pos->dns_list_node);
}
/* destory channel */
ares_destroy (pos->channel);
if (pos->status != SB_DNS_STATUS_OK)
{
pos->status = SB_DNS_STATUS_DESTORYED;
}
pos->channel = NULL;
}
}
rc = SB_OK;
/* add wait_parse_list_head to parsing_list_head */
list_for_each_entry (pos, wait_parse_list_head, list_node)
{
pos->status = SB_DNS_STATUS_PARSING;
}
list_splice_init (wait_parse_list_head, parsing_list_head);
return rc;
}
int sb_dns_main()
{
int rc = 0;
rc = sb_dns_init_env();
if (rc) {
fprintf("init dns env failed\n");
return SB_ERROR;
}
while (1) {
/* 1. */
/* 2. ܽ */
sb_dns_process();
}
return SB_OK;
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化