*** irc2.8.21+CSr23/ircd/s_bsd.c Fri Apr 5 20:22:35 1996 --- irc2.8.21+CSr24/ircd/s_bsd.c Wed Jul 24 20:25:14 1996 *************** *** 61,66 **** --- 61,72 ---- #include #include #include + + #ifdef USE_POLL + #include + #include + #endif /* USE_POLL_ */ + #ifdef AIX # include # include *************** *** 1374,1386 **** ** Do some tricky stuff for client connections to make sure they don't do ** any flooding >:-) -avalon */ ! static int read_packet(cptr, rfd) Reg1 aClient *cptr; ! fd_set *rfd; { Reg1 int dolen = 0, length = 0, done; ! if (FD_ISSET(cptr->fd, rfd) && !(IsPerson(cptr) && DBufLength(&cptr->recvQ) > 6090)) { errno = 0; --- 1380,1392 ---- ** Do some tricky stuff for client connections to make sure they don't do ** any flooding >:-) -avalon */ ! static int read_packet(cptr, msg_ready) Reg1 aClient *cptr; ! int msg_ready; { Reg1 int dolen = 0, length = 0, done; ! if (msg_ready && !(IsPerson(cptr) && DBufLength(&cptr->recvQ) > 6090)) { errno = 0; *************** *** 1489,1494 **** --- 1495,1502 ---- } + #ifndef USE_POLL + /* * Check all connections for new connections and input data that is to be * processed. Also check for connections with data queued and whether we can *************** *** 1762,1768 **** } length = 1; /* for fall through case */ if (!NoNewLine(cptr) || FD_ISSET(i, &read_set)) ! length = read_packet(cptr, &read_set); #ifndef DOG3 if (length > 0) flush_connections(i); --- 1770,1776 ---- } length = 1; /* for fall through case */ if (!NoNewLine(cptr) || FD_ISSET(i, &read_set)) ! length = read_packet(cptr, FD_ISSET(i, &read_set)); #ifndef DOG3 if (length > 0) flush_connections(i); *************** *** 1807,1812 **** --- 1815,2192 ---- } return 0; } + + #else /* USE_POLL */ + + #ifdef DOG3 + + int read_message(delay, listp) + time_t delay; /* Don't ever use ZERO here, unless you mean to poll and then + * you have to have sleep/wait somewhere else in the code.--msa + */ + fdlist *listp; + + #else + + int read_message(delay) + time_t delay; + + #endif + + { + /* + * eliminate the direct FD_ macros as they are select() specific + * and replace them with a higher level abstraction that also works for + * poll()... + */ + #define POLLREADFLAGS (POLLIN|POLLRDNORM) + #define POLLWRITEFLAGS (POLLOUT|POLLWRNORM) + #define SET_READ_EVENT( thisfd ){ CHECK_PFD( thisfd );\ + pfd->events |= POLLREADFLAGS;} + #define SET_WRITE_EVENT( thisfd ){ CHECK_PFD( thisfd );\ + pfd->events |= POLLWRITEFLAGS;} + #define CHECK_PFD( thisfd ) \ + if ( pfd->fd != thisfd ) { \ + pfd = &poll_fdarray[nbr_pfds++];\ + pfd->fd = thisfd; \ + pfd->events = 0; \ + } + + register aClient *cptr; + register int nfds; + struct timeval wait; + + #ifdef pyr + struct timeval nowt; + u_long us; + #endif + pollfd_t poll_fdarray[MAXCONNECTIONS]; + pollfd_t * pfd = poll_fdarray; + pollfd_t * res_pfd = NULL; + pollfd_t * udp_pfd = NULL; + aClient * authclnts[MAXCONNECTIONS]; /* mapping of auth fds to client */ + int nbr_pfds = 0; + time_t delay2 = delay; + u_long usec = 0; + int res, length, fd, i, fdnew; + int auth = 0; + #ifdef DOG3 + register int j; + + /* if it is called with NULL we check all active fd's */ + if (!listp) + { + listp = &default_fdlist; + listp->last_entry = highest_fd+1; /* remember the 0th entry isnt */ + } + + #endif + + #ifdef NPATH + note_delay(&delay); + #endif + #ifdef pyr + (void) gettimeofday(&nowt, NULL); + NOW = nowt.tv_sec; + #endif + + for (res = 0;;) + { + /* set up such that CHECK_FD works */ + nbr_pfds = 0; + pfd = poll_fdarray; + pfd->fd = -1; + auth = 0; + res_pfd = NULL; + udp_pfd = NULL; + + #ifndef DOG3 + for (i = highest_fd; i >= 0; i--) + #else + for (i=listp->entry[j=1];j<=listp->last_entry; + i=listp->entry[++j]) + #endif + { + if (!(cptr = local[i]) || IsLog(cptr)) + continue; + Debug((DEBUG_NOTICE, "fd %d cptr %#x %d %#x %s", + i, cptr, cptr->status, cptr->flags, + get_client_name(cptr,TRUE))); + if (DoingAuth(cptr)) + { + if ( auth == 0 ) + bzero( (char *)&authclnts, + sizeof(authclnts) ); + auth++; + Debug((DEBUG_NOTICE,"auth on %x %d", cptr, + i)); + SET_READ_EVENT(cptr->authfd); + if (cptr->flags & FLAGS_WRAUTH) + SET_WRITE_EVENT(cptr->authfd); + authclnts[cptr->authfd] = cptr; + } + if (DoingDNS(cptr) || DoingAuth(cptr)) + continue; + if (IsListening(cptr)) + { + if ((NOW > cptr->lasttime + 2)) { + SET_READ_EVENT( i ); + } + else if (delay2 > 2) + delay2 = 2; + } + else + { + if (DBufLength(&cptr->recvQ) && delay2 > 2) + delay2 = 1; + if (DBufLength(&cptr->recvQ) < 4088) + SET_READ_EVENT( i ); + } + + if (DBufLength(&cptr->sendQ) || IsConnecting(cptr)) + #ifndef pyr + SET_WRITE_EVENT( i ); + #else + { + if (!(cptr->flags & FLAGS_BLOCKED)) + SET_WRITE_EVENT( i ); + else + delay2 = 0, usec = 500000; + } + if (NOW - cptr->lw.tv_sec && + nowt.tv_usec - cptr->lw.tv_usec < 0) + us = 1000000; + else + us = 0; + us += nowt.tv_usec; + if (us - cptr->lw.tv_usec > 500000) + cptr->flags &= ~FLAGS_BLOCKED; + #endif + } + + if (udpfd >= 0) + { + SET_READ_EVENT(udpfd); + udp_pfd = pfd; + } + if (resfd >= 0) + { + SET_READ_EVENT(resfd); + res_pfd = pfd; + } + Debug((DEBUG_NOTICE, "udpfd %d resfd %d", + udpfd, resfd )); + + wait.tv_sec = MIN(delay2, delay); + wait.tv_usec = usec; + + /* do the wait */ + nfds = poll( poll_fdarray, nbr_pfds, + wait.tv_sec * 1000 + wait.tv_usec/1000); + + if (nfds == -1 && errno == EINTR) + return -1; + else if (nfds >= 0) + break; + report_error("poll %s:%s", &me); + res++; + if (res > 5) + restart("too many poll errors"); + sleep(10); + NOW = time(NULL); + } + + if (res_pfd && (res_pfd->revents & POLLREADFLAGS) ) + { + do_dns_async(); + nfds--; + res_pfd->revents &= ~POLLREADFLAGS; + } + if (udp_pfd && (udp_pfd->revents & POLLREADFLAGS) ) + { + polludp(); + nfds--; + udp_pfd->revents &= ~POLLREADFLAGS; + } + + /* + * loop through all the polled fds testing for whether any + * has an I/O ready + */ + for ( pfd = poll_fdarray, i = 0; + (nfds > 0) && (i < nbr_pfds); + i++, pfd++ ) { + + /* most tests (idle fds) should keep going here */ + if ( pfd->revents == 0 ) + continue; + + /* found something that completed */ + nfds--; + fd = pfd->fd; + + /* check for the auth completions - previously, this was it's + own loop through the fds */ + if (( auth > 0 ) && ( cptr = authclnts[fd]) && ( cptr->authfd == fd)) { + + /* auth I/O ready */ + auth--; + if (pfd->revents & POLLWRITEFLAGS) + send_authports(cptr); + else if (pfd->revents & POLLREADFLAGS) + read_authports(cptr); + continue; + } + + /* + * get the client pointer -- all the previous incarnations + * of this code embedded this test within the subsequent + * 'if' statements - put it here for reusability + */ + if ( !(cptr = local[fd])) + continue; + + /* + * accept connections + */ + if ((pfd->revents & POLLREADFLAGS) && IsListening(cptr)) + { + pfd->revents &= ~POLLREADFLAGS; + cptr->lasttime = NOW; + /* + ** There may be many reasons for error return, but + ** in otherwise correctly working environment the + ** probable cause is running out of file descriptors + ** (EMFILE, ENFILE or others?). The man pages for + ** accept don't seem to list these as possible, + ** although it's obvious that it may happen here. + ** Thus no specific errors are tested at this + ** point, just assume that connections cannot + ** be accepted until some old is closed first. + */ + if ((fdnew = accept(fd, NULL, NULL)) < 0) + { + report_error("Cannot accept connections %s:%s", + cptr); + continue; + } + ircstp->is_ac++; + if (fdnew >= MAXCLIENTS) + { + ircstp->is_ref++; + sendto_ops("All connections in use. (%s)", + get_client_name(cptr, TRUE)); + (void)send(fdnew, + "ERROR :All connections in use\r\n", + 32, 0); + (void)close(fdnew); + continue; + } + /* + * Use of add_connection (which never fails :) meLazy + */ + #ifdef UNIXPORT + if (IsUnixSocket(cptr)) + add_unixconnection(cptr, fdnew); + else + #endif + (void)add_connection(cptr, fdnew); + nextping = NOW; + continue; + } + + /* + * was the next loop - check for actual work to be done + */ + if (IsMe( cptr )) + continue; + if (pfd->revents & POLLWRITEFLAGS ) + { + int write_err = 0; + /* + ** ...room for writing, empty some queue then... + */ + if (IsConnecting(cptr)) + write_err = completed_connection(cptr); + if (!write_err) + (void)send_queued(cptr); + if (IsDead(cptr) || write_err) + { + deadsocket: + (void)exit_client(cptr, cptr, &me, + strerror(get_sockerr(cptr))); + continue; + } + } + length = 1; /* for fall through case */ + if ((!NoNewLine(cptr) || pfd->revents & POLLREADFLAGS) && + !(DoingAuth(cptr) && NOW - cptr->firsttime < 5)) + length = read_packet(cptr, ((pfd->revents & POLLREADFLAGS )!= 0)); + + readcalls++; + if (length == FLUSH_BUFFER) + continue; + else if (length > 0) + flush_connections(cptr->fd); + if (IsDead(cptr)) + goto deadsocket; + if (length > 0) + continue; + + /* Ghost! Unknown users are tagged in parse() since 2.9. + * Let's not drop the uplink but just the ghost's message. + */ + if (length == -3) + continue; + + /* + ** NB: This following section has been modofied to *expect* + ** cptr to be valid (ie if (length == FLUSH_BUFFER) is + ** above and stays there). - avalon 24/9/94 + */ + /* + ** ...hmm, with non-blocking sockets we might get + ** here from quite valid reasons, although.. why + ** would select report "data available" when there + ** wasn't... so, this must be an error anyway... --msa + ** actually, EOF occurs when read() returns 0 and + ** in due course, select() returns that fd as ready + ** for reading even though it ends up being an EOF. -avalon + */ + Debug((DEBUG_ERROR, "READ ERROR: fd = %d %d %d", + cptr->fd, errno, length)); + + if (IsServer(cptr) || IsHandshake(cptr)) + { + int timeconnected = NOW - cptr->firsttime; + + if (length == 0) + sendto_ops("Server %s closed the connection (%d, %2d:%02d:%02d)", + get_client_name(cptr, FALSE), + timeconnected / 86400, + (timeconnected % 86400) / 3600, + (timeconnected % 3600)/60, + timeconnected % 60); + else /* this must be for -1 */ + { + report_error("Lost connection to %s:%s",cptr); + sendto_ops("%s had been connected for %d, %2d:%02d:%02d", + get_client_name(cptr, FALSE), + timeconnected / 86400, + (timeconnected % 86400) / 3600, + (timeconnected % 3600)/60, + timeconnected % 60); + } + } + (void)exit_client(cptr, cptr, &me, length >= 0 ? + "EOF From client" : + strerror(get_sockerr(cptr))); + } + return 0; + } + + #endif /* USE_POLL */ + /* * connect_server