diff options
author | Jonas Gunz <himself@jonasgunz.de> | 2020-05-25 20:09:04 +0200 |
---|---|---|
committer | Jonas Gunz <himself@jonasgunz.de> | 2020-05-25 20:09:04 +0200 |
commit | 4440a86cfa359b8e40a484a2cd46d33db5455d8a (patch) | |
tree | f5c0c59aebf0058ae97e7ef8b5fb8017f459a05a /iauth/a_io.c | |
download | ircd-4440a86cfa359b8e40a484a2cd46d33db5455d8a.tar.gz |
Initial
Diffstat (limited to 'iauth/a_io.c')
-rw-r--r-- | iauth/a_io.c | 831 |
1 files changed, 831 insertions, 0 deletions
diff --git a/iauth/a_io.c b/iauth/a_io.c new file mode 100644 index 0000000..a4bd57e --- /dev/null +++ b/iauth/a_io.c @@ -0,0 +1,831 @@ +/************************************************************************ + * IRC - Internet Relay Chat, iauth/a_io.c + * Copyright (C) 1998 Christophe Kalt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef lint +static char rcsid[] = "@(#)$Id: a_io.c,v 1.22 1999/07/11 22:09:59 kalt Exp $"; +#endif + +#include "os.h" +#include "a_defines.h" +#define A_IO_C +#include "a_externs.h" +#undef A_IO_C + +anAuthData cldata[MAXCONNECTIONS]; /* index == ircd fd */ +static int cl_highest = -1; +#if defined(USE_POLL) +static int fd2cl[MAXCONNECTIONS]; /* fd -> cl mapping */ +#endif + +#define IOBUFSIZE 4096 +static char iobuf[IOBUFSIZE+1]; +static char rbuf[IOBUFSIZE+1]; /* incoming ircd stream */ +static int iob_len = 0, rb_len = 0; + +void +init_io() +{ + bzero((char *) cldata, sizeof(cldata)); +} + +/* sendto_ircd() functions */ +#if ! USE_STDARG +void +sendto_ircd(pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) +char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10; +#else +void +vsendto_ircd(char *pattern, va_list va) +#endif +{ + char ibuf[4096]; + +#if ! USE_STDARG + sprintf(ibuf, pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); +#else + vsprintf(ibuf, pattern, va); +#endif + DebugLog((ALOG_DSPY, 0, "To ircd: [%s]", ibuf)); + strcat(ibuf, "\n"); + if (write(0, ibuf, strlen(ibuf)) != strlen(ibuf)) + { + sendto_log(ALOG_DMISC, LOG_NOTICE, "Daemon exiting. [w %s]", + strerror(errno)); + exit(0); + } +} + +#if USE_STDARG +void +sendto_ircd(char *pattern, ...) +{ + va_list va; + va_start(va, pattern); + vsendto_ircd(pattern, va); + va_end(va); +} +#endif + +/* + * next_io + * + * given an entry, look for the next module instance to start + */ +static void +next_io(cl, last) +int cl; +AnInstance *last; +{ + DebugLog((ALOG_DIO, 0, "next_io(#%d, %x): last=%s state=0x%X", cl, last, + (last) ? last->mod->name : "", cldata[cl].state)); + + /* first, bail out immediately if the entry is flagged A_DONE */ + if (cldata[cl].state & A_DONE) + return; + + /* second, make sure the last instance which ran cleaned up */ + if (cldata[cl].rfd > 0 || cldata[cl].wfd > 0) + { + /* last is defined here */ + sendto_log(ALOG_IRCD|ALOG_DMISC, LOG_ERR, + "module \"%s\" didn't clean up fd's! (%d %d)", + last->mod->name, cldata[cl].rfd, cldata[cl].wfd); + if (cldata[cl].rfd > 0) + close(cldata[cl].rfd); + if (cldata[cl].wfd > 0 && cldata[cl].rfd != cldata[cl].wfd) + close(cldata[cl].wfd); + cldata[cl].rfd = cldata[cl].wfd = 0; + } + + cldata[cl].buflen = 0; + cldata[cl].mod_status = 0; + cldata[cl].instance = NULL; + cldata[cl].timeout = 0; + + /* third, if A_START is set, a new pass has to be started */ + if (cldata[cl].state & A_START) + { + cldata[cl].state ^= A_START; + DebugLog((ALOG_DIO, 0, "next_io(#%d, %x): Starting again", + cl, last)); + last = NULL; /* start from beginning */ + } + + /* fourth, find next instance to be ran */ + if (last == NULL) + { + cldata[cl].instance = instances; + cldata[cl].ileft = 0; + } + else + cldata[cl].instance = last->nexti; + + while (cldata[cl].instance) + { + int cm; + + if (CheckBit(cldata[cl].idone, cldata[cl].instance->in)) + { + DebugLog((ALOG_DIO, 0, + "conf_match(#%d, %x, goth=%d, noh=%d) skipped %x (%s)", + cl, last, (cldata[cl].state & A_GOTH) == A_GOTH, + (cldata[cl].state & A_NOH) == A_NOH, + cldata[cl].instance, + cldata[cl].instance->mod->name)); + cldata[cl].instance = cldata[cl].instance->nexti; + continue; + } + cm = conf_match(cl, cldata[cl].instance); + DebugLog((ALOG_DIO, 0, + "conf_match(#%d, %x, goth=%d, noh=%d) said \"%s\" for %x (%s)", + cl, last, (cldata[cl].state & A_GOTH) == A_GOTH, + (cldata[cl].state & A_NOH) == A_NOH, + (cm==-1) ? "no match" : (cm==0) ? "match" : "try again", + cldata[cl].instance, cldata[cl].instance->mod->name)); + if (cm == 0) + break; + if (cm == -1) + SetBit(cldata[cl].idone, cldata[cl].instance->in); + else /* cm == 1 */ + cldata[cl].ileft += 1; + cldata[cl].instance = cldata[cl].instance->nexti; + } + + if (cldata[cl].instance == NULL) + /* fifth, when there's no instance to try.. */ + { + DebugLog((ALOG_DIO, 0, + "next_io(#%d, %x): no more instances to try (%d)", + cl, last, cldata[cl].ileft)); + if (cldata[cl].ileft == 0) + { + /* we are done */ + sendto_ircd("D %d %s %u ", cl, cldata[cl].itsip, + cldata[cl].itsport); + cldata[cl].state |= A_DONE; + free(cldata[cl].inbuffer); + cldata[cl].inbuffer = NULL; + } + return; + } + else + /* sixth, we've got an instance to try */ + { + int r; + + cldata[cl].timeout = time(NULL) + cldata[cl].instance->timeout; + r = cldata[cl].instance->mod->start(cl); + DebugLog((ALOG_DIO, 0, + "next_io(#%d, %x): %s->start() returned %d", + cl, last, cldata[cl].instance->mod->name, r)); + if (r != 1) + /* started, or nothing to do or failed: don't try again */ + SetBit(cldata[cl].idone, cldata[cl].instance->in); + if (r == 1) + cldata[cl].ileft += 1; + if (r != 0) + /* start() didn't start something */ + next_io(cl, cldata[cl].instance); + } +} + +/* + * parse_ircd + * + * parses data coming from ircd (doh ;-) + */ +static void +parse_ircd() +{ + char *ch, *chp, *buf = iobuf; + int cl = -1, ncl; + + iobuf[iob_len] = '\0'; + while (ch = index(buf, '\n')) + { + *ch = '\0'; + DebugLog((ALOG_DSPY, 0, "parse_ircd(): got [%s]", buf)); + + cl = atoi(chp = buf); + while (*chp++ != ' '); + switch (chp[0]) + { + case 'C': /* new connection */ + case 'O': /* old connection: do nothing, just update data */ + if (cldata[cl].state & A_ACTIVE) + { + /* this is not supposed to happen!!! */ + sendto_log(ALOG_IRCD, LOG_CRIT, + "Entry %d [%c] is already active (fatal)!", + cl, chp[0]); + exit(1); + } + if (cldata[cl].instance || cldata[cl].rfd > 0 || + cldata[cl].wfd > 0) + { + sendto_log(ALOG_IRCD, LOG_CRIT, + "Entry %d [%c] is already active! (fatal)", + cl, chp[0]); + exit(1); + } + if (cldata[cl].authuser) + { + /* shouldn't be here - hmmpf */ + sendto_log(ALOG_IRCD|ALOG_DIO, LOG_WARNING, + "Unreleased data [%c %d]!", chp[0], + cl); + free(cldata[cl].authuser); + cldata[cl].authuser = NULL; + } + if (cldata[cl].inbuffer) + { + /* shouldn't be here - hmmpf */ + sendto_log(ALOG_IRCD|ALOG_DIO, LOG_WARNING, + "Unreleased buffer [%c %d]!", + chp[0], cl); + free(cldata[cl].inbuffer); + cldata[cl].inbuffer = NULL; + } + cldata[cl].user[0] = '\0'; + cldata[cl].passwd[0] = '\0'; + cldata[cl].host[0] = '\0'; + bzero(cldata[cl].idone, BDSIZE); + cldata[cl].buflen = 0; + if (chp[0] == 'C') + cldata[cl].state = A_ACTIVE; + else + { + cldata[cl].state = A_ACTIVE|A_IGNORE; + break; + } + if (sscanf(chp+2, "%[^ ] %hu %[^ ] %hu", + cldata[cl].itsip, &cldata[cl].itsport, + cldata[cl].ourip, &cldata[cl].ourport) != 4) + { + sendto_log(ALOG_IRCD, LOG_CRIT, + "Bad data from ircd [%s] (fatal)", + chp); + exit(1); + } + /* we should really be using a pool of buffer here */ + cldata[cl].inbuffer = malloc(INBUFSIZE+1); + if (cl > cl_highest) + cl_highest = cl; + next_io(cl, NULL); /* get started */ + break; + case 'D': /* client disconnect */ + if (!(cldata[cl].state & A_ACTIVE)) + /* + ** this is not fatal, it happens with servers + ** we connected to (and more?). + ** It's better/safer to ignore here rather + ** than try to filter in ircd. -kalt + */ + sendto_log(ALOG_IRCD, LOG_WARNING, + "Warning: Entry %d [D] is not active.", cl); + cldata[cl].state = 0; + if (cldata[cl].rfd > 0 || cldata[cl].wfd > 0) + cldata[cl].instance->mod->clean(cl); + cldata[cl].instance = NULL; + /* log something here? hmmpf */ + if (cldata[cl].authuser) + free(cldata[cl].authuser); + cldata[cl].authuser = NULL; + if (cldata[cl].inbuffer) + free(cldata[cl].inbuffer); + cldata[cl].inbuffer = NULL; + break; + case 'R': /* fd remap */ + if (!(cldata[cl].state & A_ACTIVE)) + { + /* this should really not happen */ + sendto_log(ALOG_IRCD, LOG_CRIT, + "Entry %d [R] is not active!", cl); + break; + } + ncl = atoi(chp+2); + if (cldata[ncl].state & A_ACTIVE) + { + /* this is not supposed to happen!!! */ + sendto_log(ALOG_IRCD, LOG_CRIT, + "Entry %d [R] is already active (fatal)!", ncl); + exit(1); + } + if (cldata[ncl].instance || cldata[ncl].rfd > 0 || + cldata[ncl].wfd > 0) + { + sendto_log(ALOG_IRCD, LOG_CRIT, + "Entry %d is already active! (fatal)", + ncl); + exit(1); + } + if (cldata[ncl].authuser) + { + /* shouldn't be here - hmmpf */ + sendto_log(ALOG_IRCD|ALOG_DIO, LOG_WARNING, + "Unreleased data [%d]!", ncl); + free(cldata[ncl].authuser); + cldata[ncl].authuser = NULL; + } + if (cldata[ncl].inbuffer) + { + /* shouldn't be here - hmmpf */ + sendto_log(ALOG_IRCD|ALOG_DIO, LOG_WARNING, + "Unreleased buffer [%c %d]!", + chp[0], ncl); + free(cldata[ncl].inbuffer); + cldata[ncl].inbuffer = NULL; + } + bcopy(cldata+cl, cldata+ncl, sizeof(anAuthData)); + + cldata[cl].state = 0; + cldata[cl].rfd = cldata[cl].wfd = 0; + cldata[cl].instance = NULL; + cldata[cl].authuser = NULL; + cldata[cl].inbuffer = NULL; + /* + ** this is the ugly part of having a slave (considering + ** that ircd remaps fd's: there is lag between the + ** server and the slave. + ** I can't think of any better way to handle this at + ** the moment -kalt + */ + if (cldata[ncl].state & A_IGNORE) + break; + if (cldata[ncl].state & A_LATE) + /* pointless 99.9% of the time */ + break; + if (cldata[ncl].authuser) + sendto_ircd("%c %d %s %u %s", + (cldata[ncl].state&A_UNIX)?'U':'u', + ncl, cldata[ncl].itsip, + cldata[ncl].itsport, + cldata[ncl].authuser); + if (cldata[ncl].state & A_DENY) + sendto_ircd("K %d %s %u ", ncl, + cldata[ncl].itsip, + cldata[ncl].itsport, + cldata[ncl].authuser); + if (cldata[ncl].state & A_DONE) + sendto_ircd("D %d %s %u ", ncl, + cldata[ncl].itsip, + cldata[ncl].itsport, + cldata[ncl].authuser); + break; + case 'N': /* hostname */ + if (!(cldata[cl].state & A_ACTIVE)) + { + /* let's be conservative and just ignore */ + sendto_log(ALOG_IRCD, LOG_WARNING, + "Warning: Entry %d [N] is not active.", cl); + break; + } + if (cldata[cl].state & A_IGNORE) + break; + strcpy(cldata[cl].host, chp+2); + cldata[cl].state |= A_GOTH|A_START; + if (cldata[cl].instance == NULL) + next_io(cl, NULL); + break; + case 'A': /* host alias */ + if (!(cldata[cl].state & A_ACTIVE)) + { + /* let's be conservative and just ignore */ + sendto_log(ALOG_IRCD, LOG_WARNING, + "Warning: Entry %d [A] is not active.", cl); + break; + } + if (cldata[cl].state & A_IGNORE) + break; + /* hmmpf */ + break; + case 'U': /* user provided username */ + if (!(cldata[cl].state & A_ACTIVE)) + { + /* let's be conservative and just ignore */ + sendto_log(ALOG_IRCD, LOG_WARNING, + "Warning: Entry %d [U] is not active.", cl); + break; + } + if (cldata[cl].state & A_IGNORE) + break; + strcpy(cldata[cl].user, chp+2); + cldata[cl].state |= A_GOTU|A_START; + if (cldata[cl].instance == NULL) + next_io(cl, NULL); + break; + case 'P': /* user provided password */ + if (!(cldata[cl].state & A_ACTIVE)) + { + /* let's be conservative and just ignore */ + sendto_log(ALOG_IRCD, LOG_WARNING, + "Warning: Entry %d [P] is not active.", cl); + break; + } + if (cldata[cl].state & A_IGNORE) + break; + strcpy(cldata[cl].passwd, chp+2); + cldata[cl].state |= A_GOTP; + /* + ** U message will follow immediately, + ** no need to do any thing else here + */ + break; + case 'T': /* ircd is registering the client */ + /* what to do with this? abort/continue? */ + cldata[cl].state |= A_LATE; + break; + case 'd': /* DNS timeout */ + case 'n': /* No hostname information, but no timeout either */ + if (!(cldata[cl].state & A_ACTIVE)) + { + /* let's be conservative and just ignore */ + sendto_log(ALOG_IRCD, LOG_WARNING, + "Warning: Entry %d [%c] is not active.", + cl, chp[0]); + break; + } + cldata[cl].state |= A_NOH|A_START; + if (cldata[cl].instance == NULL) + next_io(cl, NULL); + break; + case 'E': /* error message from ircd */ + sendto_log(ALOG_DIRCD, LOG_DEBUG, + "Error from ircd: %s", chp); + break; + default: + sendto_log(ALOG_IRCD, LOG_ERR, "Unexpected data [%s]", + chp); + break; + } + + buf = ch+1; + } + rb_len = 0; iob_len = 0; + if (strlen(buf)) + bcopy(buf, rbuf, rb_len = strlen(buf)); +} + +/* + * loop_io + * + * select()/poll() loop + */ +void +loop_io() +{ + /* the following is from ircd/s_bsd.c */ +#if ! USE_POLL +# define SET_READ_EVENT( thisfd ) FD_SET( thisfd, &read_set) +# define SET_WRITE_EVENT( thisfd ) FD_SET( thisfd, &write_set) +# define CLR_READ_EVENT( thisfd ) FD_CLR( thisfd, &read_set) +# define CLR_WRITE_EVENT( thisfd ) FD_CLR( thisfd, &write_set) +# define TST_READ_EVENT( thisfd ) FD_ISSET( thisfd, &read_set) +# define TST_WRITE_EVENT( thisfd ) FD_ISSET( thisfd, &write_set) + + fd_set read_set, write_set; + int highfd = -1; +#else +/* most of the following use pfd */ +# define POLLSETREADFLAGS (POLLIN|POLLRDNORM) +# define POLLREADFLAGS (POLLSETREADFLAGS|POLLHUP|POLLERR) +# define POLLSETWRITEFLAGS (POLLOUT|POLLWRNORM) +# define POLLWRITEFLAGS (POLLOUT|POLLWRNORM|POLLHUP|POLLERR) + +# define SET_READ_EVENT( thisfd ){ CHECK_PFD( thisfd );\ + pfd->events |= POLLSETREADFLAGS;} +# define SET_WRITE_EVENT( thisfd ){ CHECK_PFD( thisfd );\ + pfd->events |= POLLSETWRITEFLAGS;} + +# define CLR_READ_EVENT( thisfd ) pfd->revents &= ~POLLSETREADFLAGS +# define CLR_WRITE_EVENT( thisfd ) pfd->revents &= ~POLLSETWRITEFLAGS +# define TST_READ_EVENT( thisfd ) pfd->revents & POLLREADFLAGS +# define TST_WRITE_EVENT( thisfd ) pfd->revents & POLLWRITEFLAGS + +# define CHECK_PFD( thisfd ) \ + if ( pfd->fd != thisfd ) { \ + pfd = &poll_fdarray[nbr_pfds++];\ + pfd->fd = thisfd; \ + pfd->events = 0; \ + } + + struct pollfd poll_fdarray[MAXCONNECTIONS]; + struct pollfd * pfd = poll_fdarray; + int nbr_pfds = 0; +#endif + + int i, nfds = 0; + struct timeval wait; + time_t now = time(NULL); + +#if !defined(USE_POLL) + FD_ZERO(&read_set); + FD_ZERO(&write_set); + highfd = 0; +#else + /* set up such that CHECK_FD works */ + nbr_pfds = 0; + pfd = poll_fdarray; + pfd->fd = -1; +#endif /* USE_POLL */ + + SET_READ_EVENT(0); nfds = 1; /* ircd stream */ +#if defined(USE_POLL) && defined(IAUTH_DEBUG) + for (i = 0; i < MAXCONNECTIONS; i++) + fd2cl[i] = -1; /* sanity */ +#endif + for (i = 0; i <= cl_highest; i++) + { + if (cldata[i].timeout && cldata[i].timeout < now && + cldata[i].instance /* shouldn't be needed.. but it is */) + { + DebugLog((ALOG_DIO, 0, + "io_loop(): module %s timeout [%d]", + cldata[i].instance->mod->name, i)); + if (cldata[i].instance->mod->timeout(i) != 0) + next_io(i, cldata[i].instance); + } + if (cldata[i].rfd > 0) + { + SET_READ_EVENT(cldata[i].rfd); +#if !defined(USE_POLL) + if (cldata[i].rfd > highfd) + highfd = cldata[i].rfd; +#else + fd2cl[cldata[i].rfd] = i; +#endif + nfds++; + } + else if (cldata[i].wfd > 0) + { + SET_WRITE_EVENT(cldata[i].wfd); +#if ! USE_POLL + if (cldata[i].wfd > highfd) + highfd = cldata[i].wfd; +#else + fd2cl[cldata[i].wfd] = i; +#endif + nfds++; + } + } + + DebugLog((ALOG_DIO, 0, "io_loop(): checking for %d fd's", nfds)); + wait.tv_sec = 5; wait.tv_usec = 0; +#if ! USE_POLL + nfds = select(highfd + 1, (SELECT_FDSET_TYPE *)&read_set, + (SELECT_FDSET_TYPE *)&write_set, 0, &wait); + DebugLog((ALOG_DIO, 0, "io_loop(): select() returned %d, errno = %d", + nfds, errno)); +#else + nfds = poll(poll_fdarray, nbr_pfds, + wait.tv_sec * 1000 + wait.tv_usec/1000 ); + DebugLog((ALOG_DIO, 0, "io_loop(): poll() returned %d, errno = %d", + nfds, errno)); + pfd = poll_fdarray; +#endif + if (nfds == -1) + if (errno == EINTR) + return; + else + { + sendto_log(ALOG_IRCD, LOG_CRIT, + "fatal select/poll error: %s", + strerror(errno)); + exit(1); + } + if (nfds == 0) /* end of timeout */ + return; + + /* no matter select() or poll() this is also fd # 0 */ + if (TST_READ_EVENT(0)) + nfds--; + +#if !defined(USE_POLL) + for (i = 0; i <= cl_highest && nfds; i++) +#else + for (pfd = poll_fdarray+1; pfd != poll_fdarray+nbr_pfds && nfds; pfd++) +#endif + { +#if defined(USE_POLL) + i = fd2cl[pfd->fd]; +# if defined(IAUTH_DEBUG) + if (i == -1) + { + sendto_log(ALOG_DALL, LOG_CRIT,"io_loop(): fatal bug"); + exit(1); + } +# endif +#endif + if (cldata[i].rfd <= 0 && cldata[i].wfd <= 0) + { +#if defined(USE_POLL) + sendto_log(ALOG_IRCD, LOG_CRIT, + "io_loop(): fatal data inconsistency #%d (%d, %d)", + i, cldata[i].rfd, cldata[i].wfd); + exit(1); +#else + continue; +#endif + } + if (cldata[i].rfd > 0 && TST_READ_EVENT(cldata[i].rfd)) + { + int len; + + len = recv(cldata[i].rfd, + cldata[i].inbuffer + cldata[i].buflen, + INBUFSIZE - cldata[i].buflen, 0); + DebugLog((ALOG_DIO, 0, "io_loop(): i = #%d: recv(%d) returned %d, errno = %d", i, cldata[i].rfd, len, errno)); + if (len < 0) + { + cldata[i].instance->mod->clean(i); + next_io(i, cldata[i].instance); + } + else + { + cldata[i].buflen += len; + if (cldata[i].instance->mod->work(i) != 0) + next_io(i, cldata[i].instance); + else if (len == 0) + { + cldata[i].instance->mod->clean(i); + next_io(i, cldata[i].instance); + } + } + nfds--; + } + else if (cldata[i].wfd > 0 && TST_WRITE_EVENT(cldata[i].wfd)) + { + if (cldata[i].instance->mod->work(i) != 0) + next_io(i, cldata[i].instance); + + nfds--; + } + } + + /* + ** no matter select() or poll() this is also fd # 0 + ** this has to be done last (for the USE_POLL version) because + ** of R messages we may get from the server :/ + */ +#if defined(USE_POLL) + pfd = poll_fdarray; +#endif + if (TST_READ_EVENT(0)) + { + /* data from the ircd.. */ + while (1) + { + if (rb_len) + bcopy(rbuf, iobuf, iob_len = rb_len); + if ((i=recv(0,iobuf+iob_len,IOBUFSIZE-iob_len,0)) <= 0) + { + DebugLog((ALOG_DIO, 0, "io_loop(): recv(0) returned %d, errno = %d", i, errno)); + break; + } + iob_len += i; + DebugLog((ALOG_DIO, 0, + "io_loop(): got %d bytes from ircd [%d]", i, + iob_len)); + parse_ircd(); + } + if (i == 0) + { + sendto_log(ALOG_DMISC, LOG_NOTICE, + "Daemon exiting. [r]"); + exit(0); + } + } + +#if defined(IAUTH_DEBUG) + if (nfds > 0) + sendto_log(ALOG_DIO, 0, "io_loop(): nfds = %d !!!", nfds); +# if !defined(USE_POLL) + /* the equivalent should be written for poll() */ + if (nfds == 0) + while (i <= cl_highest) + { + if (cldata[i].rfd > 0 && TST_READ_EVENT(cldata[i].rfd)) + { + /* this should not happen! */ + /* hmmpf */ + } + i++; + } +# endif +#endif +} + +/* + * set_non_blocking (ripped from ircd/s_bsd.c) + */ +static void +set_non_blocking(fd, ip, port) +int fd; +char *ip; +u_short port; +{ + int res, nonb = 0; + +#if NBLOCK_POSIX + nonb |= O_NONBLOCK; +#endif +#if NBLOCK_BSD + nonb |= O_NDELAY; +#endif +#if NBLOCK_SYSV + /* This portion of code might also apply to NeXT. -LynX */ + res = 1; + + if (ioctl (fd, FIONBIO, &res) < 0) + sendto_log(ALOG_IRCD, 0, "ioctl(fd,FIONBIO) failed for %s:%u", + ip, port); +#else + if ((res = fcntl(fd, F_GETFL, 0)) == -1) + sendto_log(ALOG_IRCD, 0, "fcntl(fd, F_GETFL) failed for %s:%u", + ip, port); + else if (fcntl(fd, F_SETFL, res | nonb) == -1) + sendto_log(ALOG_IRCD, 0, + "fcntl(fd, F_SETL, nonb) failed for %s:%u", + ip, port); +#endif +} + +/* + * tcp_connect + * + * utility function for use in modules, creates a socket and connects + * it to an IP/port + * + * Returns the fd + */ +int +tcp_connect(ourIP, theirIP, port, error) +char *ourIP, *theirIP, **error; +u_short port; +{ + int fd; + static char errbuf[BUFSIZ]; + struct SOCKADDR_IN sk; + + fd = socket(AFINET, SOCK_STREAM, 0); + if (fd < 0) + { + sprintf(errbuf, "socket() failed: %s", strerror(errno)); + *error = errbuf; + return -1; + } + /* + * this bzero() shouldn't be needed.. should it? + * AIX 4.1.5 doesn't like not having it tho.. I have no clue why -kalt + */ + bzero((char *)&sk, sizeof(sk)); + sk.SIN_FAMILY = AFINET; +#if defined(INET6) + if(!inet_pton(AF_INET6, ourIP, sk.sin6_addr.s6_addr)) + bcopy(minus_one, sk.sin6_addr.s6_addr, IN6ADDRSZ); +#else + sk.sin_addr.s_addr = inetaddr(ourIP); +#endif + sk.SIN_PORT = htons(0); + if (bind(fd, (SAP)&sk, sizeof(sk)) < 0) + { + sprintf(errbuf, "bind() failed: %s", strerror(errno)); + *error = errbuf; + close(fd); + return -1; + } + set_non_blocking(fd, theirIP, port); +#if defined(INET6) + if(!inet_pton(AF_INET6, theirIP, sk.sin6_addr.s6_addr)) + bcopy(minus_one, sk.sin6_addr.s6_addr, IN6ADDRSZ); +#else + sk.sin_addr.s_addr = inetaddr(theirIP); +#endif + sk.SIN_PORT = htons(port); + if (connect(fd, (SAP)&sk, sizeof(sk)) < 0 && errno != EINPROGRESS) + { + sprintf(errbuf, "connect() to %s %u failed: %s", theirIP, port, + strerror(errno)); + *error = errbuf; + close(fd); + return -1; + } + *error = NULL; + return fd; +} |