--- ircd-hybrid-7/include/dbuf.h Tue Jan 4 15:00:02 2000 +++ ircd-hybrid-7-with-green-31337-modz/include/dbuf.h Sat Jul 8 21:25:32 2000 @@ -35,6 +35,7 @@ ** this package maintaining the buffer on disk, either] */ struct DBufBuffer; +struct Client; /* ** These structure definitions are only here to be used @@ -65,6 +66,17 @@ extern int dbuf_put(struct DBuf* dyn, const char* buf, size_t len); /* +** dbuf_put_sendQ +** Append the number of bytes to the buffer, allocating more +** memory as needed. Bytes are copied into internal buffers +** from users buffer. +** +** returns > 0, if operation successfull +** < 0, if failed (due memory allocation problem) +*/ +extern int dbuf_put_sendQ(struct Client* cptr, const char* buf, size_t len); + +/* ** dbuf_get ** Remove number of bytes from the buffer, releasing dynamic ** memory, if applicaple. Bytes are copied from internal buffers @@ -111,6 +123,7 @@ */ extern const char* dbuf_map(const struct DBuf* dyn, size_t* len); extern void dbuf_delete(struct DBuf* dyn, size_t len); +extern void dbuf_delete_sendQ(struct Client* cptr, size_t len); /* ** DBufLength --- ircd-hybrid-7/include/s_auth.h Thu Dec 30 23:38:28 1999 +++ ircd-hybrid-7-with-green-31337-modz/include/s_auth.h Sat Jul 8 21:57:11 2000 @@ -51,15 +51,39 @@ #define ClearDNSPending(x) ((x)->flags &= ~AM_DNS_PENDING) #define IsDNSPending(x) ((x)->flags & AM_DNS_PENDING) +#ifdef USE_KQUEUE +#define SetAuthConnect(x) do { \ + (x)->flags |= AM_AUTH_CONNECTING; \ + (void)kqueue_add(kq_auth, (x)->fd, x); \ +} while (0) +#define ClearAuthConnect(x) do { \ + (void)kqueue_delete(kq_auth, (x)->fd, x); \ + (x)->flags &= ~AM_AUTH_CONNECTING; \ + (void)kqueue_add(kq_auth, (x)->fd, x); \ +} while (0) +#define IsAuthConnect(x) ((x)->flags & AM_AUTH_CONNECTING) +#else #define SetAuthConnect(x) ((x)->flags |= AM_AUTH_CONNECTING) #define ClearAuthConnect(x) ((x)->flags &= ~AM_AUTH_CONNECTING) #define IsAuthConnect(x) ((x)->flags & AM_AUTH_CONNECTING) +#endif #define SetAuthPending(x) ((x)->flags |= AM_AUTH_PENDING) #define ClearAuthPending(x) ((x)->flags &= AM_AUTH_PENDING) #define IsAuthPending(x) ((x)->flags & AM_AUTH_PENDING) -#define ClearAuth(x) ((x)->flags &= ~(AM_AUTH_PENDING | AM_AUTH_CONNECTING)) +#ifdef KQUEUE +#define ClearAuth(x) do { \ + ClearAuthConnect(x); \ + ClearAuthPending(x); \ + (void)kqueue_delete(kq_auth, (x)->fd, x); \ +} while (0) +#else +#define ClearAuth(x) do { \ + ClearAuthConnect(x); \ + ClearAuthPending(x); \ +} while (0) +#endif #define IsDoingAuth(x) ((x)->flags & (AM_AUTH_PENDING | AM_AUTH_CONNECTING)) /* #define SetGotId(x) ((x)->flags |= FLAGS_GOTID) */ --- ircd-hybrid-7/src/dbuf.c Wed Jan 5 17:57:03 2000 +++ ircd-hybrid-7-with-green-31337-modz/src/dbuf.c Sat Jul 8 21:57:35 2000 @@ -28,8 +28,13 @@ #include "irc_string.h" #include "ircd_defs.h" #include "send.h" +#include "client.h" +#include "kqueue.h" +#include "s_bsd.h" +#include "s_log.h" #include +#include #include #include #include @@ -204,6 +209,29 @@ return 0; } +int +dbuf_put_sendQ(struct Client *to, const char *buf, size_t length) { + int put; +#ifdef USE_KQUEUE + size_t oldlen; + + oldlen = DBufLength(&to->sendQ); +#endif /* USE_KQUEUE */ + put = dbuf_put(&to->sendQ, buf, length); + if (put == 1) { + send_queued(to); +#ifdef USE_KQUEUE + if (DBufLength(&to->sendQ) != 0 && oldlen == 0 && + kqueue_add(kq_send, to->fd, NULL) == -1) { + log(L_ERROR, "kqueue_add in dbuf_put_sendQ fails: %s", + strerror(errno)); + return (dbuf_malloc_error(&to->sendQ)); + } +#endif /* USE_KQUEUE */ + } + return (put); +} + /* * dbuf_put - put a sequence of bytes in a dbuf */ @@ -303,6 +331,15 @@ dyn->tail = 0; dyn->length = 0; } +} + +void +dbuf_delete_sendQ(struct Client *cptr, size_t length) { +#ifdef USE_KQUEUE + if (length >= cptr->sendQ.length) + (void)kqueue_delete(kq_send, cptr->fd, cptr); +#endif + dbuf_delete(&cptr->sendQ, length); } size_t dbuf_get(struct DBuf* dyn, char* buf, size_t length) --- ircd-hybrid-7/src/fdlist.c Thu Dec 30 15:35:44 1999 +++ ircd-hybrid-7-with-green-31337-modz/src/fdlist.c Sat Jul 8 19:18:16 2000 @@ -25,6 +25,7 @@ } } +#ifndef USE_KQUEUE void fdlist_add(int fd, unsigned char mask) { assert(fd < MAXCONNECTIONS + 1); @@ -36,6 +37,7 @@ assert(fd < MAXCONNECTIONS + 1); GlobalFDList[fd] &= ~mask; } +#endif /* !USE_KQUEUE */ #ifndef NO_PRIORITY #ifdef CLIENT_SERVER --- ircd-hybrid-7/src/ircd.c Sun Apr 2 23:37:02 2000 +++ ircd-hybrid-7-with-green-31337-modz/src/ircd.c Sat Jul 8 22:24:03 2000 @@ -51,6 +51,7 @@ #include "scache.h" #include "send.h" #include "whowas.h" +#include "kqueue.h" #include #include @@ -820,6 +821,9 @@ initialize_message_files(); +#ifdef USE_KQUEUE + kqueue_init(); +#endif dbuf_init(); /* set up some dbuf stuff to control paging */ init_hash(); --- ircd-hybrid-7/src/listener.c Thu Dec 30 15:35:46 1999 +++ ircd-hybrid-7-with-green-31337-modz/src/listener.c Sat Jul 8 21:57:44 2000 @@ -26,8 +26,10 @@ #include "numeric.h" #include "s_bsd.h" #include "s_conf.h" +#include "s_log.h" #include "s_stats.h" #include "send.h" +#include "kqueue.h" #include #include @@ -244,6 +246,13 @@ listener = make_listener(port, vaddr); if (inetport(listener)) { +#ifdef USE_KQUEUE + if (kqueue_add(kq_listener, listener->fd, listener) == -1) { + log(L_ERROR, "Failed to register listener on kqueue."); + free_listener(listener); + return; + } +#endif listener->active = 1; listener->next = ListenerPollList; ListenerPollList = listener; @@ -279,8 +288,12 @@ } } } - if (-1 < listener->fd) + if (-1 < listener->fd) { +#ifdef USE_KQUEUE + (void)kqueue_delete(kq_listener, listener->fd, listener); +#endif close(listener->fd); + } free_listener(listener); } --- ircd-hybrid-7/src/res.c Sun Apr 2 11:54:36 2000 +++ ircd-hybrid-7-with-green-31337-modz/src/res.c Sat Jul 8 22:40:46 2000 @@ -21,6 +21,7 @@ #include "s_log.h" #include "send.h" #include "s_debug.h" +#include "kqueue.h" #include #include @@ -326,6 +327,16 @@ #endif if (ResolverFileDescriptor < 0) { ResolverFileDescriptor = socket(AF_INET, SOCK_DGRAM, 0); + if (ResolverFileDescriptor == -1) + log(L_ERROR, "resolver socket creation: %s", strerror(errno)); +#ifdef USE_KQUEUE + log(L_NOTICE, "adding resolver %d to kqueue %d", kq_resolver, + ResolverFileDescriptor); + if (kqueue_add(kq_resolver, ResolverFileDescriptor, NULL) == -1) { + log(L_CRIT, "Couldn't add resolver to kqueue: %s", strerror(errno)); + exit(1); + } +#endif /* USE_KQUEUE */ set_non_blocking(ResolverFileDescriptor); } } --- ircd-hybrid-7/src/s_auth.c Thu Dec 30 23:12:51 1999 +++ ircd-hybrid-7-with-green-31337-modz/src/s_auth.c Sat Jul 8 21:36:09 2000 @@ -40,6 +40,7 @@ #include "s_log.h" #include "s_stats.h" #include "send.h" +#include "kqueue.h" #include /* struct hostent */ #include @@ -573,9 +574,9 @@ } } + ClearAuth(auth); close(auth->fd); auth->fd = -1; - ClearAuth(auth); if (!s) { ++ServerStats->is_abad; --- ircd-hybrid-7/src/s_bsd.c Tue Feb 1 21:57:17 2000 +++ ircd-hybrid-7-with-green-31337-modz/src/s_bsd.c Sat Jul 8 23:58:00 2000 @@ -42,6 +42,7 @@ #include "s_zip.h" #include "send.h" #include "s_debug.h" +#include "kqueue.h" #include #include @@ -951,7 +952,7 @@ * processed. Also check for connections with data queued and whether we can * write it out. */ -#ifndef USE_POLL +#if !defined(USE_POLL) && !defined(USE_KQUEUE) int read_message(time_t delay, unsigned char mask) /* mika */ /* Don't ever use ZERO here, unless you mean to poll @@ -1171,7 +1172,7 @@ return 0; } -#else /* USE_POLL */ +#elif defined(USE_POLL) #if defined(POLLMSG) && defined(POLLIN) && defined(POLLRDNORM) #define POLLREADFLAGS (POLLMSG | POLLIN | POLLRDNORM) @@ -1447,5 +1448,128 @@ return 0; } -#endif /* USE_POLL */ +#else /* USE_KQUEUE */ + +/* + * For now, the CONNECTFAST case is always true. It's not really bad + * anymore, anyway. + */ +int +read_message(time_t delay, unsigned char mask) +{ + struct kevent kq_kevents[5], kevents[MAXCONNECTIONS]; + struct kevent *kev, *kqp; + struct Client *cptr; + int kqnfds; + int nfds; + struct timespec wait; + + int res = 0; + int length; + struct AuthRequest *auth; + struct Listener *listener; + int i; + + for (;;) { + wait.tv_sec = delay; + wait.tv_nsec = 0; + kqnfds = kevent(kq_kqueues, 0, NULL, 5, kq_kevents, &wait); + i = errno; + if ((CurrentTime = time(0)) == -1) { + log(L_CRIT, "Clock Failure"); + restart("Clock failed"); + } + if (kqnfds == -1 && (i == EINTR || i == EAGAIN)) + return (-1); + else if (kqnfds >= 0) + break; + report_error("kqueue %s:%s", me.name, errno); + res++; + if (res > 5) + restart("too many kqueue errors"); + sleep(10); + } + wait.tv_sec = 0; + wait.tv_nsec = 0; + for (kqp = &kq_kevents[0]; kqp < &kq_kevents[kqnfds]; kqp++) { + if (kqp->ident == kq_resolver) { + /* + * I can ignore the kq_resolver here; it will + * just return true, anyway :) + */ + get_res(); + } else if (kqp->ident == kq_auth) { + nfds = kevent(kq_auth, 0, NULL, MAXCONNECTIONS, + kevents, &wait); + if (nfds == -1) { + log(L_ERROR, "kevent failed: %s", + strerror(errno)); + continue; + } + for (kev = &kevents[0]; kev < &kevents[nfds]; kev++) { + auth = kev->udata; + if (IsAuthConnect(auth)) + send_auth_query(auth); + else + read_auth_reply(auth); + } + } else if (kqp->ident == kq_listener) { + nfds = kevent(kq_listener, 0, NULL, MAXCONNECTIONS, + kevents, &wait); + if (nfds == -1) { + log(L_ERROR, "kevent failed: %s", + strerror(errno)); + continue; + } + for (kev = &kevents[0]; kev < &kevents[nfds]; kev++) { + listener = kev->udata; + accept_connection(listener); + } + } else if (kqp->ident == kq_client) { + nfds = kevent(kq_client, 0, NULL, MAXCONNECTIONS, + kevents, &wait); + if (nfds == -1) { + log(L_ERROR, "kevent failed: %s", + strerror(errno)); + continue; + } + for (kev = &kevents[0]; kev < &kevents[nfds]; kev++) { + cptr = kev->udata; + length = read_packet(cptr); + if (length > 0 || length == CLIENT_EXITED) + continue; + if (IsDead(cptr)) + exit_client(cptr, cptr, &me, + strerror(get_sockerr(cptr->fd))); + else + error_exit_client(cptr, length); + } + } else if (kqp->ident == kq_send) { + nfds = kevent(kq_send, 0, NULL, MAXCONNECTIONS, + kevents, &wait); + if (nfds == -1) { + log(L_ERROR, "kevent failed: %s", + strerror(errno)); + continue; + } + for (kev = &kevents[0]; kev < &kevents[nfds]; kev++) { + cptr = kev->udata; + if (IsConnecting(cptr) && + !completed_connection(cptr)) { + exit_client(cptr, cptr, &me, + "Lost C/N Line"); + continue; + } + send_queued(cptr); + if (IsDead(cptr)) + exit_client(cptr, cptr, &me, + (cptr->flags & FLAGS_SENDQEX) ? + "SendQ Exceeded" : + strerror(get_sockerr(cptr->fd))); + } + } + } + return (0); +} +#endif /* USE_KQUEUE */ --- ircd-hybrid-7/src/send.c Fri Apr 7 08:39:00 2000 +++ ircd-hybrid-7-with-green-31337-modz/src/send.c Wed May 24 01:59:27 2000 @@ -35,6 +35,7 @@ #include "s_conf.h" #include "list.h" #include "s_debug.h" +#include "kqueue.h" #include #include @@ -101,6 +102,7 @@ */ void flush_connections(struct Client* cptr) { +#ifndef USE_KQUEUE if (0 == cptr) { int i; for (i = highest_fd; i >= 0; --i) { @@ -110,6 +112,7 @@ } else if (-1 < cptr->fd && DBufLength(&cptr->sendQ) > 0) send_queued(cptr); +#endif /* !USE_KQUEUE */ } /* @@ -190,7 +193,7 @@ if (to->flags2 & FLAGS2_ZIP) msg = zip_buffer(to, msg, &len, 0); - if (len && !dbuf_put(&to->sendQ, msg, len)) + if (len && !dbuf_put_sendQ(to, msg, len)) return dead_link(to, "Buffer allocation error for %s"); } @@ -266,7 +269,7 @@ if (len == -1) return dead_link(to, "fatal error in zip_buffer()"); - if (!dbuf_put(&to->sendQ, msg, len)) + if (!dbuf_put_sendQ(to, msg, len)) return dead_link(to, "Buffer allocation error for %s"); } } /* if ((to->flags2 & FLAGS2_ZIP) && to->zip->outcount) */ @@ -278,7 +281,7 @@ if ((rlen = deliver_it(to, msg, len)) < 0) return dead_link(to,"Write error to %s, closing link"); - dbuf_delete(&to->sendQ, rlen); + dbuf_delete_sendQ(to, rlen); to->lastsq = DBufLength(&to->sendQ) / 1024; /* * sendq is now empty.. if there a blocked list? @@ -309,7 +312,7 @@ if (len == -1) return dead_link(to, "fatal error in zip_buffer()"); - if (!dbuf_put(&to->sendQ, msg, len)) + if (!dbuf_put_sendQ(to, msg, len)) return dead_link(to, "Buffer allocation error for %s"); } /* if (DBufLength(&to->sendQ) == 0 && more) */ } /* while (DBufLength(&to->sendQ) > 0) */ --- ircd-hybrid-7/src/version.c.SH Thu Dec 30 15:36:12 1999 +++ ircd-hybrid-7-with-green-31337-modz/src/version.c.SH Sat Jul 8 18:47:17 2000 @@ -85,6 +85,7 @@ "comstud Chris Behrens cbehrens@concentric.net", "Dianora Diane Bruce db@db.net", "echo Adam J. Durana adam@caca.com", + "green_ Brian F. Feldman green@FreeBSD.org", "FlashMan Craig A. Huegen chuegen@quadrunner.com", "jailbird Dustin Marquess jailbird@alcatraz.fdf.net", "johan Johannes Erdfelt jerdfelt@eng.mindspring.net", --- /dev/null Sun Jul 9 00:07:19 2000 +++ ircd-hybrid-7-with-green-31337-modz/include/kqueue.h Sat Jul 8 21:56:11 2000 @@ -0,0 +1,20 @@ +/* + * $Id$ + */ + +#ifndef KQUEUE_H +#define KQUEUE_H + +#ifdef USE_KQUEUE +#include +#include + +extern int kq_resolver, kq_auth, kq_listener, kq_client, kq_send, kq_kqueues; + +void kqueue_init(void); +int kqueue_add(int kq, int fd, void *userdata); +int kqueue_delete(int kq, int fd, void *userdata); + +#endif /* USE_KQUEUE */ + +#endif /* KQUEUE_H */ --- /dev/null Sun Jul 9 00:14:29 2000 +++ ircd-hybrid-7-with-green-31337-modz/src/s_kqueue.c Sat Jul 8 23:16:39 2000 @@ -0,0 +1,134 @@ +/*- + * Copyright (c) 2000 Brian Fundakowski Feldman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + */ + +#ifdef USE_KQUEUE +#include "config.h" +#include "ircd.h" +#include "s_auth.h" +#include "s_log.h" +#include "kqueue.h" +#include "fdlist.h" +#include "client.h" + +#include +#include +#include + +int kq_resolver, kq_auth, kq_listener, kq_client, kq_send, kq_kqueues; + +static const struct kevent kevent_zero = { 0, 0, 0, 0, 0, NULL }; +static const struct timespec timespec_zero = { 0, 0 }; + +void +kqueue_init(void) { + + if ((kq_resolver = kqueue()) == -1 || + (kq_auth = kqueue()) == -1 || + (kq_listener = kqueue()) == -1 || + (kq_client = kqueue()) == -1 || + (kq_send = kqueue()) == -1 || + (kq_kqueues = kqueue()) == -1 || + kqueue_add(kq_kqueues, kq_resolver, NULL) == -1 || + kqueue_add(kq_kqueues, kq_auth, NULL) == -1 || + kqueue_add(kq_kqueues, kq_listener, NULL) == -1 || + kqueue_add(kq_kqueues, kq_client, NULL) == -1 || + kqueue_add(kq_kqueues, kq_send, NULL) == -1) { + log(L_CRIT, "kqueue creation error: %s", strerror(errno)); + exit(1); + } +} + +int +kqueue_add(int kq, int fd, void *userdata) { + struct kevent ke, *kep = &ke; + struct timespec ts = timespec_zero; + + ke = kevent_zero; + ke.ident = fd; + if (kq == kq_send) + ke.filter = EVFILT_WRITE; + else if (kq == kq_auth) { + if (IsAuthConnect((struct AuthRequest *)userdata)) + ke.filter = EVFILT_WRITE; + else + ke.filter = EVFILT_READ; + } else + ke.filter = EVFILT_READ; + ke.flags = EV_ADD | EV_CLEAR; + if (ke.filter == EVFILT_WRITE) + ke.flags |= EV_ONESHOT; + ke.udata = userdata; + + return (kevent(kq, 1, &kep, 0, NULL, &ts)); +} + +int +kqueue_delete(int kq, int fd, void *userdata) { + struct kevent ke, *kep = &ke; + struct timespec ts = timespec_zero; + + ke = kevent_zero; + ke.ident = fd; + if (kq == kq_send) + ke.filter = EVFILT_WRITE; + else if (kq == kq_auth) { + if (IsAuthConnect((struct AuthRequest *)userdata)) + ke.filter = EVFILT_WRITE; + else + ke.filter = EVFILT_READ; + } else + ke.filter = EVFILT_READ; + ke.flags = EV_DELETE; + + return (kevent(kq, 1, &kep, 0, NULL, &ts)); +} + +void +fdlist_add(int fd, unsigned char mask) { + + if (GlobalFDList[fd] != 0) { + GlobalFDList[fd] |= mask; + return; + } else + GlobalFDList[fd] |= mask; + if (kqueue_add(kq_client, fd, local[fd]) == -1) { + log(L_ERROR, "client kqueue_add failure: %s", + strerror(errno)); + (void)exit_client(NULL, local[fd], &me, "kqueue trouble"); + } +} + +void +fdlist_delete(int fd, unsigned char mask) { + + GlobalFDList[fd] &= ~mask; + if (GlobalFDList[fd] == 0) + (void)kqueue_delete(kq_client, fd, NULL); +} + +#endif /* USE_KQUEUE */