################## GNU adns resolver patch for CircleMUD 3.0 ##################
      Date: May 23, 2000
   Version: 1.00
  Codebase: CircleMUD 3.0 bpl 17
    Author: Juliano Ravasi Ferraz <jferraz@linkway.com.br>
  
     Many imps have problems with theyr muds getting frozen because the ip
  address resolving system used (gethostbyaddr()). When your nameserver gets
  broken or lagged, on the next time a player connect to the mud, it freezes
  completely while gethostbyaddr attempts to get hostname.
  
     There is a command (slowns) that disables hostname resolving, but it has
  three main problems:
     1) You will only be able to disable hostname resolving AFTER felling that
        your mud is getting frozen;
     2) May be that your mud will have no imps online when your nameserver
        gets lagged;
     3) Disabling hostname resolving, some targets of your banlist will be
        disabled too, leaving your server open to bad people.
  
     This patch will make your mud leave this work to a shared library called
  GNU adns, written by Ian Jackson and Tony Finch. When a player connects onto
  your mud, it will send the IP address to libadns and continues normal game
  loop while adns resolves the ip address in background.
  
     To use this patch, you will need the gnu adns library compiled and
  installed on your system and a copy of the adns.h header file on your src/
  directory. To get the adns source code, browse to the address below, unpack
  and follow instructions on the INSTALL file.
   http://www.chiark.greenend.org.uk/~ian/adns/
  
     After putting a copy of adns.h on your src/ directory, you have two
  different ways to apply this patch to your code:
     1) if you have made no changes on your mud, or if you are felling
        too lucky, simply enter the directory you installed your mud and
        type: patch -p0 < adns-bpl17.patch
     2) continue reading down this file, and apply the patch manually to
        each file.
  
     This patch was not tested so much, so, it may have bugs. It worked on a
  Linux 2.2.5, gcc 2.91.66, GNU libc 2.1.1 and libadns 0.7.
  
     You don't need to give me credits if you use this patch, but I will be
  much happy on having some bytes of your credits file. :-)
  
     Send asks or bug reports to <jferraz@linkway.com.br>.
     Send flames to /dev/null.

diff -pruN src/Makefile src.adns/Makefile
--- src/Makefile	Fri Jan 28 16:38:13 2000
+++ src.adns/Makefile	Thu Apr  6 19:53:13 2000
@@ -22,7 +22,7 @@ 
 
 CFLAGS = -g -O2 $(MYFLAGS) $(PROFILE)
 
-LIBS =  -lcrypt 
+LIBS =  -lcrypt -ladns 
 
 OBJFILES = act.comm.o act.informative.o act.item.o act.movement.o \
 	act.offensive.o act.other.o act.social.o act.wizard.o alias.o ban.o \
@@ -132,8 +132,8 
 class.o: class.c conf.h sysdep.h structs.h db.h utils.h spells.h interpreter.h \
   constants.h
 	$(CC) -c $(CFLAGS) class.c
-comm.o: comm.c conf.h sysdep.h structs.h utils.h comm.h interpreter.h handler.h \
-  db.h house.h
+comm.o: comm.c conf.h sysdep.h adns.h structs.h utils.h comm.h interpreter.h \
+  handler.h db.h house.h
 	$(CC) -c $(CFLAGS) comm.c
 config.o: config.c conf.h sysdep.h structs.h interpreter.h
 	$(CC) -c $(CFLAGS) config.c
diff -pruN src/comm.c src.adns/comm.c
--- src/comm.c	Sun Jan 23 18:21:32 2000
+++ src.adns/comm.c	Tue May 23 22:33:13 2000
@@ -48,6 +48,7 @@
  * files that is included is controlled by conf.h for that platform.
  */
 
+#include "adns.h"
 #include "structs.h"
 #include "utils.h"
 #include "comm.h"
@@ -90,6 +91,7 @@ 
 
 /* local globals */
 struct descriptor_data *descriptor_list = NULL;		/* master desc list */
+struct nslookup_data *nslookup_list = NULL;	/* adns lookups list */
 struct txt_block *bufpool = 0;	/* pool of large output buffers */
 int buf_largecount = 0;		/* # of large buffers which exist */
 int buf_overflows = 0;		/* # of overflows of output */
@@ -120,7 +122,8 @@ 
 void signal_setup(void);
 void game_loop(socket_t mother_desc);
 socket_t init_socket(ush_int port);
-int new_descriptor(socket_t s);
+int new_descriptor(socket_t s, adns_state adns);
+int init_descriptor(struct descriptor_data *d, const char *hostname);
 int get_max_players(void);
 int process_output(struct descriptor_data *t);
 int process_input(struct descriptor_data *t);
@@ -564,6 +567,11 @@ void game_loop(socket_t mother_desc)
   struct descriptor_data *d, *next_d;
   int pulse = 0, missed_pulses, maxdesc, aliased;
 
+  /* used with adns */
+  adns_state adns = NULL;
+  adns_answer *answer;
+  struct nslookup_data *dns, *nextdns, *temp;
+
   /* initialize various time values */
   null_time.tv_sec = 0;
   null_time.tv_usec = 0;
@@ -573,6 +581,13 @@ void game_loop(socket_t mother_desc)
 
   gettimeofday(&last_time, (struct timezone *) 0);
 
+  /* Initialize adns library */
+  if ((errno = adns_init(&adns, 0, NULL))) {
+    log("SYSERR: Can't initialize adns service, falling to normal nslookup mode.");
+    log("adns_init: %s", strerror(errno));
+    adns = NULL;
+  }
+
   /* The Main Loop.  The Big Cheese.  The Top Dog.  The Head Honcho.  The.. */
   while (!circle_shutdown) {
 
@@ -652,7 +667,23 @@ void game_loop(socket_t mother_desc)
     }
     /* If there are new connections waiting, accept them. */
     if (FD_ISSET(mother_desc, &input_set))
-      new_descriptor(mother_desc);
+      new_descriptor(mother_desc, adns);
+
+    /* Check for resolved names */
+    for (dns = nslookup_list; dns; dns = nextdns) {
+      nextdns = dns->next;
+      if (adns_check(adns, &dns->query, &answer, NULL) != EAGAIN) {
+	/* Got response from adns */
+	SEND_TO_Q("\e[G\e[2K", dns->desc);	// Erase wait message
+	dns->desc->has_prompt = 0;		// Don't add \r\n before this
+	if (answer->status == adns_s_ok)
+	  init_descriptor(dns->desc, *answer->rrs.str);
+	else
+	  init_descriptor(dns->desc, NULL);
+	REMOVE_FROM_LIST(dns, nslookup_list, next);
+	free(dns); free(answer);
+      }
+    }
 
     /* Kick out the freaky folks in the exception set and marked for close */
     for (d = descriptor_list; d; d = next_d) {
@@ -744,7 +775,8 @@ void game_loop(socket_t mother_desc)
     /* Kick out folks in the CON_CLOSE or CON_DISCONNECT state */
     for (d = descriptor_list; d; d = next_d) {
       next_d = d->next;
-      if (STATE(d) == CON_CLOSE || STATE(d) == CON_DISCONNECT)
+      if (STATE(d) == CON_CLOSE || STATE(d) == CON_DISCONNECT ||
+	  STATE(d) == CON_REJECT)
 	close_socket(d);
     }
 
@@ -779,6 +811,7 @@ void game_loop(socket_t mother_desc)
     tics++;
 #endif
   }
+  adns_finish(adns);
 }
 
 
@@ -1180,7 +1213,7 @@ int set_sendbuf(socket_t s)
   return (0);
 }
 
-int new_descriptor(int s)
+int new_descriptor(int s, adns_state adns)
 {
   socket_t desc;
   int sockets_connected = 0;
@@ -1189,6 +1222,7 @@ int new_descriptor(int s)
   struct descriptor_data *newd;
   struct sockaddr_in peer;
   struct hostent *from;
+  struct nslookup_data *dns;
 
   /* accept the new connection */
   i = sizeof(peer);
@@ -1218,40 +1252,10 @@ int new_descriptor(int s)
   CREATE(newd, struct descriptor_data, 1);
   memset((char *) newd, 0, sizeof(struct descriptor_data));
 
-  /* find the sitename */
-  if (nameserver_is_slow || !(from = gethostbyaddr((char *) &peer.sin_addr,
-				      sizeof(peer.sin_addr), AF_INET))) {
-
-    /* resolution failed */
-    if (!nameserver_is_slow)
-      perror("SYSERR: gethostbyaddr");
-
-    /* find the numeric site address */
-    strncpy(newd->host, (char *)inet_ntoa(peer.sin_addr), HOST_LENGTH);
-    *(newd->host + HOST_LENGTH) = '\0';
-  } else {
-    strncpy(newd->host, from->h_name, HOST_LENGTH);
-    *(newd->host + HOST_LENGTH) = '\0';
-  }
-
-  /* determine if the site is banned */
-  if (isbanned(newd->host) == BAN_ALL) {
-    CLOSE_SOCKET(desc);
-    sprintf(buf2, "Connection attempt denied from [%s]", newd->host);
-    mudlog(buf2, CMP, LVL_GOD, TRUE);
-    free(newd);
-    return (0);
-  }
-#if 0
-  /*
-   * Log new connections - probably unnecessary, but you may want it.
-   * Note that your immortals may wonder if they see a connection from
-   * your site, but you are wizinvis upon login.
-   */
-  sprintf(buf2, "New connection from [%s]", newd->host);
-  mudlog(buf2, CMP, LVL_GOD, FALSE);
-#endif
-
+  /* find the numeric site address */
+  strncpy(newd->host, (char *)inet_ntoa(peer.sin_addr), HOST_LENGTH);
+  *(newd->host + HOST_LENGTH) = '\0';
+  
   /* initialize descriptor data */
   newd->descriptor = desc;
   newd->idle_tics = 0;
@@ -1260,8 +1264,8 @@ int new_descriptor(int s)
   newd->login_time = time(0);
   *newd->output = '\0';
   newd->bufptr = 0;
-  newd->has_prompt = 1;  /* prompt is part of greetings */
-  STATE(newd) = CON_GET_NAME;
+  newd->has_prompt = 0;
+  STATE(newd) = CON_NSLOOKUP;
 
   /*
    * This isn't exactly optimal but allows us to make a design choice.
@@ -1278,7 +1282,62 @@ int new_descriptor(int s)
   newd->next = descriptor_list;
   descriptor_list = newd;
 
-  SEND_TO_Q(GREETINGS, newd);
+  /* find the hostname */
+  if (!nameserver_is_slow) {
+    if (adns) {
+      SEND_TO_Q("*** Resolving your hostname...", newd);
+      CREATE(dns, struct nslookup_data, 1);
+      dns->desc = newd;
+      dns->next = nslookup_list;
+      nslookup_list = dns;
+      if (adns_submit_reverse(adns, (struct sockaddr *) &peer, adns_r_ptr,
+	      adns_qf_quoteok_cname | adns_qf_cname_loose, NULL, &dns->query)) {
+	log("SYSERR: adns_submit: %s", strerror(errno));
+      }
+      return (0);	// Stop here, leave init_descriptor() to game_loop()
+    } else {
+      if ((from = gethostbyaddr((char *) &peer.sin_addr,
+				 sizeof(peer.sin_addr), AF_INET))) {
+        strncpy(newd->host, from->h_name, HOST_LENGTH);
+	*(newd->host + HOST_LENGTH) = '\0';
+      } else
+        perror("SYSERR: gethostbyaddr");
+    }
+  }
+  
+  init_descriptor(newd, NULL);
+
+  return (0);
+}
+
+int init_descriptor(struct descriptor_data *d, const char *hostname)
+{
+  if (hostname) {
+    /* received a hostname, update descriptor data */
+    strncpy(d->host, hostname, HOST_LENGTH);
+    *(d->host + HOST_LENGTH) = '\0';
+  }
+  
+  /* determine if the site is banned */
+  if (isbanned(d->host) == BAN_ALL) {
+    SEND_TO_Q("*** Your site is banned, go away.\r\n", d);
+    STATE(d) = CON_REJECT;
+    sprintf(buf2, "Connection attempt denied from [%s]", d->host);
+    mudlog(buf2, CMP, LVL_GOD, TRUE);
+    return (0);
+  }
+#if 0
+  /*
+   * Log new connections - probably unnecessary, but you may want it.
+   * Note that your immortals may wonder if they see a connection from
+   * your site, but you are wizinvis upon login.
+   */
+  sprintf(buf2, "New connection from [%s]", d->host);
+  mudlog(buf2, CMP, LVL_GOD, FALSE);
+#endif
+
+  STATE(d) = CON_GET_NAME;
+  SEND_TO_Q(GREETINGS, d);
 
   return (0);
 }
@@ -1773,6 +1832,20 @@ int perform_subst(struct descriptor_data
 }
 
 
+void cancel_adns_query(struct descriptor_data *d)
+{
+  struct nslookup_data *dns, *nextdns, *temp;
+  
+  for (dns = nslookup_list; dns; dns = nextdns) {
+    nextdns = dns->next;
+    if (d == dns->desc) {
+      adns_cancel(dns->query);
+      REMOVE_FROM_LIST(dns, nslookup_list, next);
+      free(dns);
+    }
+  }
+}
+
 
 void close_socket(struct descriptor_data *d)
 {
@@ -1783,6 +1856,9 @@ void close_socket(struct descriptor_data
   CLOSE_SOCKET(d->descriptor);
   flush_queues(d);
 
+  /* Cancel adns query, if any */
+  cancel_adns_query(d);
+
   /* Forget snooping */
   if (d->snooping)
     d->snooping->snoop_by = NULL;
@@ -1815,7 +1891,7 @@ void close_socket(struct descriptor_data
       mudlog(buf, CMP, LVL_IMMORT, TRUE);
       free_char(d->character);
     }
-  } else
+  } else if (STATE(d) != CON_REJECT)
     mudlog("Losing descriptor without char.", CMP, LVL_IMMORT, TRUE);
 
   /* JE 2/22/95 -- part of my unending quest to make switch stable */
diff -pruN src/constants.c src.adns/constants.c
--- src/constants.c	Sun Aug 29 01:12:23 1999
+++ src.adns/constants.c	Thu Apr  6 19:48:46 2000
@@ -235,6 +235,8 @@ const char *connected_types[] = {
   "Self-Delete 1",
   "Self-Delete 2",
   "Disconnecting",
+  "NS Lookup",
+  "Disconnecting",
   "\n"
 };
 
diff -pruN src/structs.h src.adns/structs.h
--- src/structs.h	Thu Jan 20 22:20:16 2000
+++ src.adns/structs.h	Thu Apr  6 18:00:49 2000
@@ -246,6 +246,8 @@
 #define CON_DELCNF1	 15		/* Delete confirmation 1	*/
 #define CON_DELCNF2	 16		/* Delete confirmation 2	*/
 #define CON_DISCONNECT	 17		/* In-game disconnection	*/
+#define CON_NSLOOKUP	 18		/* Resolving hostname		*/
+#define CON_REJECT	 19		/* Rejecting conn (siteban)	*/
 
 /* Character equipment positions: used as index for char_data.equipment[] */
 /* NOTE: Don't confuse these constants with the ITEM_ bitvectors
@@ -529,6 +531,17 @@ 
  * extra flexibility.
  */
 typedef unsigned long int	bitvector_t;
+
+
+/* Structure used in nameserver lookups */
+#ifdef __COMM_C__
+struct nslookup_data {
+   struct descriptor_data *desc;  /* Pointer to descriptor	      */
+   adns_query query;		  /* Query data			      */
+   struct nslookup_data *next;	  /* Next in list		      */
+};
+#endif
+
 
 /* Extra description: used in objects, mobiles, and rooms */
 struct extra_descr_data {
