# HG changeset patch
# User William Pitcock <nenolod@dereferenced.org>
# Date 1349408564 0
# Node ID 904313880832e8b648bec20a6fe07088ad4827ff
# Parent  b774480aa8c8cc16e427f3f9a95c70cb3ba3fa9c
- Add support for proper FD accounting (rewrite of the fdlist code).
  This is the first step to adding evented I/O.  Infact, writing the evented I/O code
  should now be quite easy.

diff -r b774480aa8c8 -r 904313880832 include/fdlist.h
--- a/include/fdlist.h	Sat Aug 25 18:19:06 2012 +0300
+++ b/include/fdlist.h	Fri Oct 05 03:42:44 2012 +0000
@@ -3,6 +3,28 @@
 
 /* $Id$ */
 
+#define FD_DESC_SZ	(100)
+
+typedef void (*IOCallbackFunc)(int fd, void *data);
+
+typedef struct fd_entry {
+	int fd;
+	char desc[FD_DESC_SZ];
+	IOCallbackFunc read_callback;
+	IOCallbackFunc write_callback;
+	void *data;
+	time_t deadline;
+	unsigned char is_open;
+} FDEntry;
+
+extern MODVAR FDEntry fd_table[MAXCONNECTIONS + 1];
+
+extern int fd_open(int fd, const char *desc);
+extern void fd_close(int fd);
+extern int fd_socket(int family, int type, int protocol, const char *desc);
+extern int fd_accept(int sockfd);
+extern void fd_desc(int fd, const char *desc);
+
 typedef struct fdstruct {
 	int  entry[MAXCONNECTIONS + 2];
 	int  last_entry;
diff -r b774480aa8c8 -r 904313880832 src/fdlist.c
--- a/src/fdlist.c	Sat Aug 25 18:19:06 2012 +0300
+++ b/src/fdlist.c	Fri Oct 05 03:42:44 2012 +0000
@@ -28,6 +28,111 @@
 #include "proto.h"
 #include <string.h>
 
+/* new FD management code, based on mowgli.eventloop from atheme, hammered into Unreal by
+ * me, nenolod.
+ */
+FDEntry fd_table[MAXCONNECTIONS + 1];
+
+int fd_open(int fd, const char *desc)
+{
+	FDEntry *fde;
+
+	if ((fd < 0) || (fd >= MAXCONNECTIONS))
+	{
+		sendto_realops("[BUG] trying to add fd #%d to fd table, but MAXCONNECTIONS is %d",
+				fd, MAXCONNECTIONS);
+		ircd_log(LOG_ERROR, "[BUG] trying to add fd #%d to fd table, but MAXCONNECTIONS is %d",
+				fd, MAXCONNECTIONS);
+		return -1;
+	}
+
+	fde = &fd_table[fd];
+	memset(fde, 0, sizeof(FDEntry));
+
+	fde->fd = fd;
+	fde->is_open = 1;
+	strlcpy(fde->desc, desc, FD_DESC_SZ);
+
+	return fde->fd;
+}
+
+void fd_close(int fd)
+{
+	FDEntry *fde;
+
+	if ((fd < 0) || (fd >= MAXCONNECTIONS))
+	{
+		sendto_realops("[BUG] trying to close fd #%d in fd table, but MAXCONNECTIONS is %d",
+				fd, MAXCONNECTIONS);
+		ircd_log(LOG_ERROR, "[BUG] trying to close fd #%d in fd table, but MAXCONNECTIONS is %d",
+				fd, MAXCONNECTIONS);
+		return;
+	}
+
+	fde = &fd_table[fd];
+	if (!fde->is_open)
+	{
+		sendto_realops("[BUG] trying to close fd #%d in fd table, but this FD isn't reported open",
+				fd, MAXCONNECTIONS);
+		ircd_log(LOG_ERROR, "[BUG] trying to close fd #%d in fd table, but this FD isn't reported open",
+				fd, MAXCONNECTIONS);
+		return;
+	}
+
+	memset(fde, 0, sizeof(FDEntry));
+
+	CLOSE_SOCK(fd);
+}
+
+int fd_socket(int family, int type, int protocol, const char *desc)
+{
+	int fd;
+
+	fd = socket(family, type, protocol);
+	if (fd < 0)
+		return -1;
+
+	return fd_open(fd, desc);
+}
+
+int fd_accept(int sockfd)
+{
+	const char buf[] = "Incoming connection";
+	int fd;
+
+	fd = accept(sockfd, NULL, NULL);
+	if (fd < 0)
+		return -1;
+
+	return fd_open(fd, buf);
+}
+
+void fd_desc(int fd, const char *desc)
+{
+	FDEntry *fde;
+
+	if ((fd < 0) || (fd >= MAXCONNECTIONS))
+	{
+		sendto_realops("[BUG] trying to modify fd #%d in fd table, but MAXCONNECTIONS is %d",
+				fd, MAXCONNECTIONS);
+		ircd_log(LOG_ERROR, "[BUG] trying to modify fd #%d in fd table, but MAXCONNECTIONS is %d",
+				fd, MAXCONNECTIONS);
+		return;
+	}
+
+	fde = &fd_table[fd];
+	if (!fde->is_open)
+	{
+		sendto_realops("[BUG] trying to modify fd #%d in fd table, but this FD isn't reported open",
+				fd, MAXCONNECTIONS);
+		ircd_log(LOG_ERROR, "[BUG] trying to modify fd #%d in fd table, but this FD isn't reported open",
+				fd, MAXCONNECTIONS);
+		return;
+	}
+
+	strlcpy(fde->desc, desc, FD_DESC_SZ);
+}
+
 extern fdlist default_fdlist;
 extern fdlist busycli_fdlist;
 extern fdlist serv_fdlist;
diff -r b774480aa8c8 -r 904313880832 src/ircd.c
--- a/src/ircd.c	Sat Aug 25 18:19:06 2012 +0300
+++ b/src/ircd.c	Fri Oct 05 03:42:44 2012 +0000
@@ -650,7 +650,7 @@
 				if (!IsRegistered(cptr) && (DoingDNS(cptr) || DoingAuth(cptr)))
 				{
 					if (cptr->authfd >= 0) {
-						CLOSE_SOCK(cptr->authfd);
+						fd_close(cptr->authfd);
 						--OpenFiles;
 						cptr->authfd = -1;
 						cptr->count = 0;
diff -r b774480aa8c8 -r 904313880832 src/modules/m_nick.c
--- a/src/modules/m_nick.c	Sat Aug 25 18:19:06 2012 +0300
+++ b/src/modules/m_nick.c	Fri Oct 05 03:42:44 2012 +0000
@@ -116,7 +116,7 @@
 	int ishold;
 	aClient *acptr, *serv = NULL;
 	aClient *acptrs;
-	char nick[NICKLEN + 2], *s;
+	char nick[NICKLEN + 2], *s, descbuf[BUFSIZE];
 	Membership *mp;
 	time_t lastnick = (time_t) 0;
 	int  differ = 1, update_watch = 1;
@@ -770,6 +770,11 @@
 		if (IsPerson(sptr))
 			hash_check_watch(sptr, RPL_LOGOFF);
 	}
+
+	/* update fdlist --nenolod */
+	snprintf(descbuf, sizeof descbuf, "Client: %s", nick);
+	fd_desc(sptr->fd, descbuf);
+
 	(void)strcpy(sptr->name, nick);
 	(void)add_to_client_hash_table(nick, sptr);
 	if (IsServer(cptr) && parc > 7)
@@ -1049,6 +1054,11 @@
 
 	if (MyConnect(sptr))
 	{
+		char descbuf[BUFSIZE];
+
+		snprintf(descbuf, sizeof descbuf, "Client: %s", nick);
+		fd_desc(sptr->fd, descbuf);
+
 		IRCstats.unknown--;
 		IRCstats.me_clients++;
 		if (IsHidden(sptr))
diff -r b774480aa8c8 -r 904313880832 src/modules/m_server.c
--- a/src/modules/m_server.c	Sat Aug 25 18:19:06 2012 +0300
+++ b/src/modules/m_server.c	Fri Oct 05 03:42:44 2012 +0000
@@ -311,6 +311,7 @@
 	char *servername = NULL;	/* Pointer for servername */
  /*	char *password = NULL; */
 	char *ch = NULL;	/* */
+	char descbuf[BUFSIZE];
 	char *inpath = get_client_name(cptr, TRUE);
 	int  hop = 0, numeric = 0;
 	char info[REALLEN + 61];
@@ -526,6 +527,10 @@
 		}
 		if (aconf->options & CONNECT_QUARANTINE)
 			cptr->flags |= FLAGS_QUARANTINE;
+
+		snprintf(descbuf, sizeof descbuf, "Server: %s", servername);
+		fd_desc(cptr->fd, descbuf);
+
 		/* Start synch now */
 		if (m_server_synch(cptr, numeric, aconf) == FLUSH_BUFFER)
 			return FLUSH_BUFFER;
diff -r b774480aa8c8 -r 904313880832 src/modules/m_stats.c
--- a/src/modules/m_stats.c	Sat Aug 25 18:19:06 2012 +0300
+++ b/src/modules/m_stats.c	Fri Oct 05 03:42:44 2012 +0000
@@ -119,6 +119,7 @@
 int stats_zip(aClient *, char *);
 int stats_officialchannels(aClient *, char *);
 int stats_spamfilter(aClient *, char *);
+int stats_fdtable(aClient *, char *);
 
 #define SERVER_AS_PARA 0x1
 #define FLAGS_AS_PARA 0x2
@@ -152,6 +153,7 @@
 	{ 'T', "traffic",	stats_traffic,		0 		},
 	{ 'U', "uline",		stats_uline,		0 		},
 	{ 'V', "vhost", 	stats_vhost,		0 		},
+	{ 'W', "fdtable",       stats_fdtable,          0               },
 	{ 'X', "notlink",	stats_notlink,		0 		},	
 	{ 'Y', "class",		stats_class,		0 		},	
 	{ 'Z', "mem",		stats_mem,		0 		},
@@ -310,6 +312,8 @@
 	sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, sptr->name,
 		"V - vhost - Send the vhost block list");
 	sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, sptr->name,
+		"W - fdtable - Send the FD table listing");
+	sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, sptr->name,
 		"X - notlink - Send the list of servers that are not current linked");
 	sendto_one(sptr, rpl_str(RPL_STATSHELP), me.name, sptr->name,
 		"Y - class - Send the class block list");
@@ -799,6 +803,23 @@
 	return 0;
 }
 
+int stats_fdtable(aClient *sptr, char *para)
+{
+	int i;
+
+	for (i = 0; i < MAXCONNECTIONS; i++)
+	{
+		FDEntry *fde = &fd_table[i];
+
+		if (!fde->is_open)
+			continue;
+
+		sendto_one(sptr,
+			":%s %d %s :fd %3d, desc '%s', read-hdl %p, write-hdl %p, cbdata %p",
+			me.name, RPL_STATSDEBUG, sptr->name,
+			fde->fd, fde->desc, fde->read_callback, fde->write_callback, fde->data);
+	}
+}
 
 int stats_uline(aClient *sptr, char *para)
 {
diff -r b774480aa8c8 -r 904313880832 src/res.c
--- a/src/res.c	Sat Aug 25 18:19:06 2012 +0300
+++ b/src/res.c	Fri Oct 05 03:42:44 2012 +0000
@@ -81,13 +81,14 @@
 
 static DNSCache *cache_list = NULL; /**< Linked list of cache */
 static DNSCache *cache_hashtbl[DNS_HASH_SIZE]; /**< Hash table of cache */
+static ares_socket_t aresfds[ARES_GETSOCK_MAXNUM];
 
 static unsigned int unrealdns_num_cache = 0; /**< # of cache entries in memory */
 
 void init_resolver(int firsttime)
 {
 struct ares_options options;
-int n;
+int n, v, k;
 int optmask;
 
 	if (requests)
@@ -139,10 +140,17 @@
 			NAME_SERVER);
 		MyFree(options.servers);
 	}
+
+	memset(&aresfds, 0, sizeof(aresfds));
+	v = ares_getsock(resolver_channel, aresfds, ARES_GETSOCK_MAXNUM);
+	for (k = 0; k < ARES_GETSOCK_MAXNUM; k++)
+		fd_open(aresfds[k], "DNS Resolver Socket");
 }
 
 void reinit_resolver(aClient *sptr)
 {
+	int k;
+
 #ifdef CHROOTDIR
 	/* Prevent people from killing their ircd accidently if in CHROOTDIR mode... */
 FILE *fd;
@@ -159,6 +167,9 @@
 	fclose(fd);
 #endif
 
+	for (k = 0; k < ARES_GETSOCK_MAXNUM; k++)
+		fd_close(aresfds[k]);
+
 	sendto_realops("%s requested reinitalization of resolver!", sptr->name);
 	sendto_realops("Destroying resolver channel, along with all currently pending queries...");
 	ares_destroy(resolver_channel);
diff -r b774480aa8c8 -r 904313880832 src/s_auth.c
--- a/src/s_auth.c	Sat Aug 25 18:19:06 2012 +0300
+++ b/src/s_auth.c	Fri Oct 05 03:42:44 2012 +0000
@@ -50,7 +50,7 @@
 	ircstp->is_abad++;
 	if (cptr->authfd != -1)
 	{
-		CLOSE_SOCK(cptr->authfd);
+		fd_close(cptr->authfd);
 		--OpenFiles;
 		cptr->authfd = -1;
 	}
@@ -74,14 +74,16 @@
 {
 	struct SOCKADDR_IN sock, us;
 	int len;
-	
+	char buf[BUFSIZE];
+
 	if (IDENT_CHECK == 0) {
 		cptr->flags &= ~(FLAGS_WRAUTH | FLAGS_AUTH);
 		return;
 	}
 	Debug((DEBUG_NOTICE, "start_auth(%x) slot=%d, fd=%d, status=%d",
 	    cptr, cptr->slot, cptr->fd, cptr->status));
-	if ((cptr->authfd = socket(AFINET, SOCK_STREAM, 0)) == -1)
+	snprintf(buf, sizeof buf, "identd: %s", get_client_name(cptr, TRUE));
+	if ((cptr->authfd = fd_socket(AFINET, SOCK_STREAM, 0, buf)) == -1)
 	{
 		Debug((DEBUG_ERROR, "Unable to create auth socket for %s:%s",
 		    get_client_name(cptr, TRUE), strerror(get_sockerr(cptr))));
@@ -91,7 +93,7 @@
     if (++OpenFiles >= (MAXCONNECTIONS - 2))
 	{
 		sendto_ops("Can't allocate fd, too many connections.");
-		CLOSE_SOCK(cptr->authfd);
+		fd_close(cptr->authfd);
 		--OpenFiles;
 		cptr->authfd = -1;
 		return;
@@ -230,7 +232,7 @@
 		Debug((DEBUG_ERROR, "bad auth reply in [%s]", cptr->buffer));
 		*ruser = '\0';
 	}
-    CLOSE_SOCK(cptr->authfd);
+    fd_close(cptr->authfd);
     --OpenFiles;
     cptr->authfd = -1;
 	cptr->count = 0;
diff -r b774480aa8c8 -r 904313880832 src/s_bsd.c
--- a/src/s_bsd.c	Sat Aug 25 18:19:06 2012 +0300
+++ b/src/s_bsd.c	Fri Oct 05 03:42:44 2012 +0000
@@ -271,12 +271,12 @@
     if ((cptr = local[i]) != 0)
     {
       if (cptr->fd >= 0) {
-        CLOSE_SOCK(cptr->fd);
+        fd_close(cptr->fd);
         cptr->fd = -2;
       }
       if (cptr->authfd >= 0)
       {
-        CLOSE_SOCK(cptr->authfd);
+        fd_close(cptr->authfd);
         cptr->authfd = -1;
       }
     }
@@ -450,7 +450,7 @@
 	 */
 	if (cptr->fd == -1)
 	{
-		cptr->fd = socket(AFINET, SOCK_STREAM, 0);
+		cptr->fd = fd_socket(AFINET, SOCK_STREAM, 0, "Listener socket");
 	}
 	if (cptr->fd < 0)
 	{
@@ -462,7 +462,7 @@
 	else if (++OpenFiles >= MAXCLIENTS)
 	{
 		sendto_ops("No more connections allowed (%s)", cptr->name);
-		CLOSE_SOCK(cptr->fd);
+		fd_close(cptr->fd);
 		cptr->fd = -1;
 		--OpenFiles;
 		return -1;
@@ -511,7 +511,7 @@
 				                    "and/or via sysctl.");
 			}
 #endif
-			CLOSE_SOCK(cptr->fd);
+			fd_close(cptr->fd);
 			cptr->fd = -1;
 			--OpenFiles;
 			return -1;
@@ -520,7 +520,7 @@
 	if (getsockname(cptr->fd, (struct SOCKADDR *)&server, &len))
 	{
 		report_error("getsockname failed for %s:%s", cptr);
-		CLOSE_SOCK(cptr->fd);
+		fd_close(cptr->fd);
 		cptr->fd = -1;
 		--OpenFiles;
 		return -1;
@@ -1027,7 +1027,7 @@
 
 	if (cptr->authfd >= 0)
 	{
-		CLOSE_SOCK(cptr->authfd);
+		fd_close(cptr->authfd);
 		cptr->authfd = -1;
 		--OpenFiles;
 	}
@@ -1044,7 +1044,7 @@
 			cptr->ssl = NULL;
 		}
 #endif
-		CLOSE_SOCK(cptr->fd);
+		fd_close(cptr->fd);
 		cptr->fd = -2;
 		--OpenFiles;
 		DBufClear(&cptr->sendQ);
@@ -1094,7 +1094,7 @@
 				addto_fdlist(i, &oper_fdlist);
 			}
 #endif
-			CLOSE_SOCK(j);
+			fd_close(j);
 			--OpenFiles;
 		}
 #endif
@@ -1333,7 +1333,7 @@
 			ircstp->is_ref++;
 			acptr->fd = -2;
 			free_client(acptr);
-			CLOSE_SOCK(fd);
+			fd_close(fd);
 			--OpenFiles;
 			return NULL;
 		}
@@ -1925,7 +1925,7 @@
 			    (OPT_TYPE *)&err, &len) || err)
 			{
 				ircstp->is_abad++;
-				closesocket(cptr->authfd);
+				fd_close(cptr->authfd);
 				cptr->authfd = -1;
 				--OpenFiles;
 				cptr->flags &= ~(FLAGS_AUTH | FLAGS_WRAUTH);
@@ -2002,7 +2002,7 @@
 			 */
 			for (k = 0; k < LISTEN_SIZE; k++)
 {			{
-			if ((fd = accept(cptr->fd, NULL, NULL)) < 0)
+			if ((fd = fd_accept(cptr->fd)) < 0)
 			{
 		        if ((ERRNO != P_EWOULDBLOCK) && (ERRNO != P_ECONNABORTED))
 					report_baderror("Cannot accept connections %s:%s", cptr);
@@ -2045,7 +2045,7 @@
 				    "ERROR :All connections in use\r\n",
 				    31, 0, 0, 0);
 #endif
-				CLOSE_SOCK(fd);
+				fd_close(fd);
 				--OpenFiles;
 				break;
                           }
@@ -2300,7 +2300,7 @@
 	{
 		if (cptr->fd >= 0)
 		{
-			CLOSE_SOCK(cptr->fd);
+			fd_close(cptr->fd);
 			--OpenFiles;
 		}
 		cptr->fd = -2;
@@ -2325,7 +2325,7 @@
 			sendto_one(by,
 			    ":%s NOTICE %s :*** Connect to host %s failed.",
 			    me.name, by->name, cptr->name);
-		CLOSE_SOCK(cptr->fd);
+		fd_close(cptr->fd);
 		--OpenFiles;
 		cptr->fd = -2;
 		free_client(cptr);
@@ -2378,12 +2378,14 @@
 {
 	static struct SOCKADDR_IN server;
 	struct hostent *hp;
+	char buf[BUFSIZE];
 
 	/*
 	 * Might as well get sockhost from here, the connection is attempted
 	 * with it so if it fails its useless.
 	 */
-	cptr->fd = socket(AFINET, SOCK_STREAM, 0);
+	snprintf(buf, sizeof buf, "Outgoing connection: %s", get_client_name(cptr, TRUE));
+	cptr->fd = fd_socket(AFINET, SOCK_STREAM, 0, buf);
 	if (cptr->fd < 0)
 	{
 		if (ERRNO == P_EMFILE)
diff -r b774480aa8c8 -r 904313880832 src/timesynch.c
--- a/src/timesynch.c	Sat Aug 25 18:19:06 2012 +0300
+++ b/src/timesynch.c	Fri Oct 05 03:42:44 2012 +0000
@@ -163,7 +163,9 @@
 	n = 0;
 	for (servname = strtoken(&p, tmptimeservbuf, ","); servname; servname = strtoken(&p, NULL, ","))
 	{
-		s[n] = socket(AF_INET, SOCK_DGRAM, 0); /* always ipv4 */
+		char buf[BUFSIZE];
+		snprintf(buf, sizeof buf, "ntp client: %s", servname);
+		s[n] = fd_socket(AF_INET, SOCK_DGRAM, 0, buf); /* always ipv4 */
 		if (s[n] < 0)
 		{
 			ircsprintf(tserr, "unable to create socket: %s [%d]", STRERROR(ERRNO), (int)ERRNO);
@@ -281,7 +283,7 @@
 
 end:
 	for (i = 0; i < numservers; i++)
-		CLOSE_SOCK(s[i]);
+		fd_close(s[i]);
 
 	return reply;
 }
