From b26207df50edcc8d230c8ae615659f60db03ef94 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Fri, 5 Oct 2012 03:42:44 +0000 Subject: [PATCH] - 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. --- include/fdlist.h | 22 +++++++++ src/fdlist.c | 105 +++++++++++++++++++++++++++++++++++++++++ src/ircd.c | 2 +- src/modules/m_nick.c | 12 ++++- src/modules/m_server.c | 5 ++ src/modules/m_stats.c | 21 +++++++++ src/res.c | 13 ++++- src/s_auth.c | 12 +++-- src/s_bsd.c | 34 ++++++------- src/timesynch.c | 6 ++- 10 files changed, 206 insertions(+), 26 deletions(-) diff --git a/include/fdlist.h b/include/fdlist.h index 7be7ebb46..b8bd3e708 100644 --- a/include/fdlist.h +++ b/include/fdlist.h @@ -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 --git a/src/fdlist.c b/src/fdlist.c index 7a27aec7a..8fcc57a3b 100644 --- a/src/fdlist.c +++ b/src/fdlist.c @@ -28,6 +28,111 @@ #include "proto.h" #include +/* 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 --git a/src/ircd.c b/src/ircd.c index 39705e97b..dd7c897d8 100644 --- a/src/ircd.c +++ b/src/ircd.c @@ -650,7 +650,7 @@ extern TS check_pings(TS currenttime) 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 --git a/src/modules/m_nick.c b/src/modules/m_nick.c index ed25e1abe..ec7fc2c39 100644 --- a/src/modules/m_nick.c +++ b/src/modules/m_nick.c @@ -116,7 +116,7 @@ DLLFUNC CMD_FUNC(m_nick) 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 @@ DLLFUNC CMD_FUNC(m_nick) 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 @@ int _register_user(aClient *cptr, aClient *sptr, char *nick, char *username, cha 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 --git a/src/modules/m_server.c b/src/modules/m_server.c index 8a43280d2..2aa3f9a6c 100644 --- a/src/modules/m_server.c +++ b/src/modules/m_server.c @@ -311,6 +311,7 @@ DLLFUNC CMD_FUNC(m_server) 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 @@ DLLFUNC CMD_FUNC(m_server) } 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 --git a/src/modules/m_stats.c b/src/modules/m_stats.c index fa0086277..6daa92aec 100644 --- a/src/modules/m_stats.c +++ b/src/modules/m_stats.c @@ -119,6 +119,7 @@ int stats_class(aClient *, char *); 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 @@ struct statstab StatsTable[] = { { '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 }, @@ -309,6 +311,8 @@ inline void stats_help(aClient *sptr) "v - denyver - Send the deny version block list"); 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, @@ -799,6 +803,23 @@ int stats_traffic(aClient *sptr, char *para) 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 --git a/src/res.c b/src/res.c index c959d0bcf..30d0a64fb 100644 --- a/src/res.c +++ b/src/res.c @@ -81,13 +81,14 @@ static DNSReq *requests = NULL; /**< Linked list of requests (pending responses) 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 @@ int optmask; 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 @@ FILE *fd; 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 --git a/src/s_auth.c b/src/s_auth.c index 71c505732..1b4398335 100644 --- a/src/s_auth.c +++ b/src/s_auth.c @@ -50,7 +50,7 @@ void ident_failed(aClient *cptr) ircstp->is_abad++; if (cptr->authfd != -1) { - CLOSE_SOCK(cptr->authfd); + fd_close(cptr->authfd); --OpenFiles; cptr->authfd = -1; } @@ -74,14 +74,16 @@ void start_auth(aClient *cptr) { 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 @@ void start_auth(aClient *cptr) 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 @@ void read_authports(aClient *cptr) 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 --git a/src/s_bsd.c b/src/s_bsd.c index 8617c40bd..1ad9863e0 100644 --- a/src/s_bsd.c +++ b/src/s_bsd.c @@ -271,12 +271,12 @@ void close_connections(void) 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 @@ int inetport(aClient *cptr, char *name, int port) */ 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 @@ int inetport(aClient *cptr, char *name, int port) 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 @@ int inetport(aClient *cptr, char *name, int port) "and/or via sysctl."); } #endif - CLOSE_SOCK(cptr->fd); + fd_close(cptr->fd); cptr->fd = -1; --OpenFiles; return -1; @@ -520,7 +520,7 @@ int inetport(aClient *cptr, char *name, int port) 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 @@ void close_connection(aClient *cptr) if (cptr->authfd >= 0) { - CLOSE_SOCK(cptr->authfd); + fd_close(cptr->authfd); cptr->authfd = -1; --OpenFiles; } @@ -1044,7 +1044,7 @@ void close_connection(aClient *cptr) cptr->ssl = NULL; } #endif - CLOSE_SOCK(cptr->fd); + fd_close(cptr->fd); cptr->fd = -2; --OpenFiles; DBufClear(&cptr->sendQ); @@ -1094,7 +1094,7 @@ void close_connection(aClient *cptr) addto_fdlist(i, &oper_fdlist); } #endif - CLOSE_SOCK(j); + fd_close(j); --OpenFiles; } #endif @@ -1333,7 +1333,7 @@ add_con_refuse: ircstp->is_ref++; acptr->fd = -2; free_client(acptr); - CLOSE_SOCK(fd); + fd_close(fd); --OpenFiles; return NULL; } @@ -1925,7 +1925,7 @@ int read_message(time_t delay, fdlist *listp) (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 @@ int read_message(time_t delay, fdlist *listp) */ 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 @@ int read_message(time_t delay, fdlist *listp) "ERROR :All connections in use\r\n", 31, 0, 0, 0); #endif - CLOSE_SOCK(fd); + fd_close(fd); --OpenFiles; break; } @@ -2300,7 +2300,7 @@ int connect_server(ConfigItem_link *aconf, aClient *by, struct hostent *hp) { if (cptr->fd >= 0) { - CLOSE_SOCK(cptr->fd); + fd_close(cptr->fd); --OpenFiles; } cptr->fd = -2; @@ -2325,7 +2325,7 @@ int connect_server(ConfigItem_link *aconf, aClient *by, struct hostent *hp) 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 *connect_inet(ConfigItem_link *aconf, aClient *cptr, int { 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 --git a/src/timesynch.c b/src/timesynch.c index ad8c2035a..04c47edc7 100644 --- a/src/timesynch.c +++ b/src/timesynch.c @@ -163,7 +163,9 @@ int succesfully_sent = 0; 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 @@ gotit: end: for (i = 0; i < numservers; i++) - CLOSE_SOCK(s[i]); + fd_close(s[i]); return reply; }