[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[or-cvs] rudimentary dns caching (of both resolves and resolve failu...
- To: or-cvs@freehaven.net
- Subject: [or-cvs] rudimentary dns caching (of both resolves and resolve failu...
- From: arma@seul.org (Roger Dingledine)
- Date: Fri, 14 Feb 2003 02:53:58 -0500 (EST)
- Delivered-to: archiver@seul.org
- Delivered-to: or-cvs-outgoing@seul.org
- Delivered-to: or-cvs@seul.org
- Delivery-date: Fri, 14 Feb 2003 02:54:05 -0500
- Reply-to: or-dev@freehaven.net
- Sender: owner-or-cvs@freehaven.net
Update of /home/or/cvsroot/src/or
In directory moria.mit.edu:/home/arma/work/onion/cvs/src/or
Modified Files:
connection_exit.c dns.c main.c onion.c or.h
Log Message:
rudimentary dns caching (of both resolves and resolve failures)
serious performance increase over non-caching
Index: connection_exit.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection_exit.c,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -d -r1.19 -r1.20
--- connection_exit.c 14 Feb 2003 04:10:22 -0000 1.19
+++ connection_exit.c 14 Feb 2003 07:53:54 -0000 1.20
@@ -150,7 +150,7 @@
circ->n_conn = n_conn;
/* send it off to the gethostbyname farm */
- if(dns_tor_to_master(n_conn) < 0) {
+ if(dns_resolve(n_conn) < 0) {
log(LOG_DEBUG,"connection_exit_begin_conn(): Couldn't queue resolve request.");
connection_remove(n_conn);
connection_free(n_conn);
Index: dns.c
===================================================================
RCS file: /home/or/cvsroot/src/or/dns.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- dns.c 6 Feb 2003 23:48:35 -0000 1.3
+++ dns.c 14 Feb 2003 07:53:54 -0000 1.4
@@ -4,6 +4,8 @@
#include "or.h"
+#define MAX_ADDRESSLEN 256
+
#define MAX_DNSSLAVES 50
#define MIN_DNSSLAVES 3 /* 1 for the tor process, 3 slaves */
@@ -11,9 +13,9 @@
int fd; /* socket to talk on */
int num_processed; /* number of times we've used this slave */
char busy; /* whether this slave currently has a task */
- char question[256]; /* the hostname that we're resolving */
+ char question[MAX_ADDRESSLEN]; /* the hostname that we're resolving */
unsigned char question_len; /* how many bytes in question */
- char answer[256]; /* the answer to the question */
+ char answer[MAX_ADDRESSLEN]; /* the answer to the question */
unsigned char answer_len; /* how many bytes in answer */
};
@@ -29,6 +31,8 @@
static int dns_assign_to_slave(int from, int to);
static int dns_master_to_tor(int from, int to);
static void dns_master_main(int fd);
+static int dns_tor_to_master(connection_t *exitconn);
+static int dns_found_answer(char *question, uint32_t answer, uint32_t valid);
int connection_dns_finished_flushing(connection_t *conn) {
@@ -41,9 +45,9 @@
int connection_dns_process_inbuf(connection_t *conn) {
unsigned char length;
- char buf[256];
+ char buf[MAX_ADDRESSLEN];
char *question;
- connection_t *exitconn;
+ uint32_t answer;
assert(conn && conn->type == CONN_TYPE_DNSMASTER);
assert(conn->state == DNSMASTER_STATE_OPEN);
@@ -75,25 +79,12 @@
question = buf+1;
log(LOG_DEBUG,"connection_dns_process_inbuf(): length %d, question '%s', strlen question %d", length, question, strlen(question));
assert(length == 4 + strlen(question) + 1);
-
- /* find the conn that question refers to. */
- exitconn = connection_get_pendingresolve_by_address(question);
-
- if(!exitconn) {
- log(LOG_DEBUG,"connection_dns_process_inbuf(): No conn -- question no longer relevant? Dropping.");
- return connection_process_inbuf(conn); /* process the remainder of the buffer */
- }
- memcpy((char *)&exitconn->addr, buf+1+length-4,4);
- exitconn->addr = ntohl(exitconn->addr); /* get it back to host order */
-
- if(connection_exit_connect(exitconn) < 0) {
- exitconn->marked_for_close = 1;
- }
+ answer = *(uint32_t *)(buf+1+length-4);
+ dns_found_answer(question, answer, (answer != 0));
return connection_process_inbuf(conn); /* process the remainder of the buffer */
}
-
/* return -1 if error, else the fd that can talk to the dns master */
int dns_master_start(void) {
connection_t *conn;
@@ -149,7 +140,7 @@
}
static void dns_slave_main(int fd) {
- char question[256];
+ char question[MAX_ADDRESSLEN];
unsigned char question_len;
struct hostent *rent;
@@ -316,7 +307,7 @@
}
static int dns_master_to_tor(int from, int to) {
- char tmp[256];
+ char tmp[MAX_ADDRESSLEN*2];
unsigned char len;
len = slave_data[from].question_len+1+slave_data[from].answer_len;
@@ -339,52 +330,6 @@
return 0;
}
-int dns_tor_to_master(connection_t *exitconn) {
- connection_t *conn;
- unsigned char len;
-
-#ifdef DO_DNS_DIRECTLY
- /* new version which does it all right here */
- struct hostent *rent;
- rent = gethostbyname(exitconn->address);
- if (!rent) {
- return -1;
- }
-
- memcpy((char *)&exitconn->addr, rent->h_addr, rent->h_length);
- exitconn->addr = ntohl(exitconn->addr); /* get it back to host order */
-
- if(connection_exit_connect(exitconn) < 0) {
- exitconn->marked_for_close = 1;
- }
- return 0;
-#endif
-
-
-
- /* old version which actually uses the dns farm */
- conn = connection_get_by_type(CONN_TYPE_DNSMASTER);
- if(!conn) {
- log(LOG_ERR,"dns_tor_to_master(): dns master nowhere to be found!");
- /* XXX should do gethostbyname right here */
- return -1;
- }
-
- len = strlen(exitconn->address);
- if(connection_write_to_buf(&len, 1, conn) < 0) {
- log(LOG_DEBUG,"dns_tor_to_master(): Couldn't write length.");
- return -1;
- }
-
- if(connection_write_to_buf(exitconn->address, len, conn) < 0) {
- log(LOG_DEBUG,"dns_tor_to_master(): Couldn't write address.");
- return -1;
- }
-
-// log(LOG_DEBUG,"dns_tor_to_master(): submitted '%s'", address);
- return 0;
-}
-
static void dns_master_main(int fd) {
int nfds=1; /* the 0th index is the tor process, the rest are slaves */
int num_slaves_busy=0;
@@ -453,5 +398,165 @@
}
assert(0); /* should never get here */
+}
+
+
+
+#include "tree.h"
+
+struct pending_connection_t {
+ struct connection_t *conn;
+ struct pending_connection_t *next;
+};
+
+struct cached_resolve {
+ SPLAY_ENTRY(cached_resolve) node;
+ char question[MAX_ADDRESSLEN]; /* the hostname to be resolved */
+ uint32_t answer; /* in host order. I know I'm horrible for assuming ipv4 */
+ char state; /* 0 is pending; 1 means answer is valid; 2 means resolve failed */
+#define CACHE_STATE_PENDING 0
+#define CACHE_STATE_VALID 1
+#define CACHE_STATE_FAILED 2
+ uint32_t expire; /* remove untouched items from cache after some time? */
+ struct pending_connection_t *pending_connections;
+ struct cached_resolve *next;
+};
+
+SPLAY_HEAD(cache_tree, cached_resolve) cache_root;
+
+static int compare_cached_resolves(struct cached_resolve *a, struct cached_resolve *b) {
+ /* make this smarter one day? */
+ return strncasecmp(a->question, b->question, MAX_ADDRESSLEN);
+}
+
+SPLAY_PROTOTYPE(cache_tree, cached_resolve, node, compare_cached_resolves);
+SPLAY_GENERATE(cache_tree, cached_resolve, node, compare_cached_resolves);
+
+void init_cache_tree(void) {
+ SPLAY_INIT(&cache_root);
+}
+
+
+/* see if the question 'exitconn->address' has been answered. if so,
+ * if resolve valid, put it into exitconn->addr and call
+ * connection_exit_connect directly. If resolve failed, return -1.
+ *
+ * Else, if seen before and pending, add conn to the pending list,
+ * and return 0.
+ *
+ * Else, if not seen before, add conn to pending list, hand to
+ * dns farm, and return 0.
+ */
+int dns_resolve(connection_t *exitconn) {
+ struct cached_resolve *new_resolve;
+ struct cached_resolve *resolve;
+ struct pending_connection_t *pending_connection;
+
+ new_resolve = malloc(sizeof(struct cached_resolve));
+ memset(new_resolve, 0, sizeof(struct cached_resolve));
+ strncpy(new_resolve->question, exitconn->address, MAX_ADDRESSLEN);
+
+ /* try adding it to the tree. if it's already there it will
+ * return it. */
+ resolve = SPLAY_INSERT(cache_tree, &cache_root, new_resolve);
+ if(resolve) { /* already there. free up new_resolve */
+ free(new_resolve);
+ switch(resolve->state) {
+ case CACHE_STATE_PENDING:
+ /* add us to the pending list */
+ pending_connection = malloc(sizeof(struct pending_connection_t));
+ pending_connection->conn = exitconn;
+ pending_connection->next = new_resolve->pending_connections;
+ new_resolve->pending_connections = pending_connection;
+
+ return dns_tor_to_master(exitconn);
+ case CACHE_STATE_VALID:
+ exitconn->addr = resolve->answer;
+ return connection_exit_connect(exitconn);
+ case CACHE_STATE_FAILED:
+ return -1;
+ }
+ } else { /* this was newly added to the tree. ask the dns farm. */
+ new_resolve->state = CACHE_STATE_PENDING;
+
+ /* add us to the pending list */
+ pending_connection = malloc(sizeof(struct pending_connection_t));
+ pending_connection->conn = exitconn;
+ pending_connection->next = new_resolve->pending_connections;
+ new_resolve->pending_connections = pending_connection;
+
+ return dns_tor_to_master(exitconn);
+ }
+
+ assert(0);
+ return 0; /* not reached; keep gcc happy */
+}
+
+static int dns_tor_to_master(connection_t *exitconn) {
+ connection_t *dnsconn;
+ unsigned char len;
+ int do_dns_directly=0;
+
+ dnsconn = connection_get_by_type(CONN_TYPE_DNSMASTER);
+
+ if(!dnsconn) {
+ log(LOG_ERR,"dns_tor_to_master(): dns master nowhere to be found!");
+ }
+
+ if(!dnsconn || do_dns_directly) {
+ /* new version which does it all right here */
+ struct hostent *rent;
+ rent = gethostbyname(exitconn->address);
+ if (!rent) {
+ return dns_found_answer(exitconn->address, 0, 0);
+ }
+ return dns_found_answer(exitconn->address, *(uint32_t *)rent->h_addr, 1);
+ }
+
+ len = strlen(exitconn->address);
+ if(connection_write_to_buf(&len, 1, dnsconn) < 0) {
+ log(LOG_DEBUG,"dns_tor_to_master(): Couldn't write length.");
+ return -1;
+ }
+
+ if(connection_write_to_buf(exitconn->address, len, dnsconn) < 0) {
+ log(LOG_DEBUG,"dns_tor_to_master(): Couldn't write address.");
+ return -1;
+ }
+
+// log(LOG_DEBUG,"dns_tor_to_master(): submitted '%s'", address);
+ return 0;
+}
+
+static int dns_found_answer(char *question, uint32_t answer, uint32_t valid) {
+ struct pending_connection_t *pend;
+ struct cached_resolve search;
+ struct cached_resolve *resolve;
+
+ strncpy(search.question, question, MAX_ADDRESSLEN);
+
+ resolve = SPLAY_FIND(cache_tree, &cache_root, &search);
+ if(!resolve) {
+ log(LOG_ERR,"dns_found_answer(): Answer to unasked question '%s'? Dropping.", question);
+ return 0;
+ }
+
+ assert(resolve->state == CACHE_STATE_PENDING);
+
+ if(valid)
+ resolve->state = CACHE_STATE_VALID;
+ else
+ resolve->state = CACHE_STATE_FAILED;
+
+ while(resolve->pending_connections) {
+ pend = resolve->pending_connections;
+ pend->conn->addr = ntohl(answer);
+ if(resolve->state == CACHE_STATE_FAILED || connection_exit_connect(pend->conn) < 0) {
+ pend->conn->marked_for_close = 1;
+ }
+ resolve->pending_connections = pend->next;
+ free(pend);
+ }
+ return 0;
}
Index: main.c
===================================================================
RCS file: /home/or/cvsroot/src/or/main.c,v
retrieving revision 1.38
retrieving revision 1.39
diff -u -d -r1.38 -r1.39
--- main.c 26 Jan 2003 09:02:24 -0000 1.38
+++ main.c 14 Feb 2003 07:53:54 -0000 1.39
@@ -159,24 +159,6 @@
return NULL;
}
-connection_t *connection_get_pendingresolve_by_address(char *address) {
- int i;
- connection_t *conn;
-
- for(i=0;i<nfds;i++) {
- conn = connection_array[i];
- if(conn->type == CONN_TYPE_EXIT &&
- conn->state == EXIT_CONN_STATE_RESOLVING &&
- !strcmp(conn->address, address)) {
- return conn;
- }
- }
- return NULL;
-}
-
-
-
-
void connection_watch_events(connection_t *conn, short events) {
assert(conn && conn->poll_index < nfds);
Index: onion.c
===================================================================
RCS file: /home/or/cvsroot/src/or/onion.c,v
retrieving revision 1.26
retrieving revision 1.27
diff -u -d -r1.26 -r1.27
--- onion.c 26 Jan 2003 09:02:24 -0000 1.26
+++ onion.c 14 Feb 2003 07:53:55 -0000 1.27
@@ -9,6 +9,7 @@
static int onion_process(circuit_t *circ);
static int onion_deliver_to_conn(aci_t aci, unsigned char *onion, uint32_t onionlen, connection_t *conn);
+static int find_tracked_onion(unsigned char *onion, uint32_t onionlen);
int decide_aci_type(uint32_t local_addr, uint16_t local_port,
uint32_t remote_addr, uint16_t remote_port) {
@@ -756,7 +757,7 @@
/* see if this onion has been seen before. if so, return 1, else
* return 0 and add the sha1 of this onion to the tree.
*/
-int find_tracked_onion(unsigned char *onion, uint32_t onionlen) {
+static int find_tracked_onion(unsigned char *onion, uint32_t onionlen) {
static struct tracked_onion *head_tracked_onions = NULL; /* linked list of tracked onions */
static struct tracked_onion *tail_tracked_onions = NULL;
@@ -764,7 +765,7 @@
struct tracked_onion *to;
/* first take this opportunity to see if there are any expired
- * onions in the tree. we know this in O(1) because the linked list
+ * onions in the tree. we know this is fast because the linked list
* 'tracked_onions' is ordered by when they were seen.
*/
while(head_tracked_onions && (head_tracked_onions->expire < now)) {
Index: or.h
===================================================================
RCS file: /home/or/cvsroot/src/or/or.h,v
retrieving revision 1.44
retrieving revision 1.45
diff -u -d -r1.44 -r1.45
--- or.h 6 Feb 2003 23:48:35 -0000 1.44
+++ or.h 14 Feb 2003 07:53:55 -0000 1.45
@@ -650,7 +650,7 @@
int connection_dns_finished_flushing(connection_t *conn);
int connection_dns_process_inbuf(connection_t *conn);
-int dns_tor_to_master(connection_t *exitconn);
+int dns_resolve(connection_t *exitconn);
int dns_master_start(void);
/********************************* main.c ***************************/
@@ -665,7 +665,6 @@
connection_t *connection_exact_get_by_addr_port(uint32_t addr, uint16_t port);
connection_t *connection_get_by_type(int type);
-connection_t *connection_get_pendingresolve_by_address(char *address);
void connection_watch_events(connection_t *conn, short events);
void connection_stop_reading(connection_t *conn);
@@ -724,7 +723,6 @@
void pad_onion(unsigned char *onion, uint32_t onionlen, int n);
void init_tracked_tree(void);
-int find_tracked_onion(unsigned char *onion, uint32_t onionlen);
/********************************* routers.c ***************************/