/*
- * $Id$
- *
- * DEBUG: section 05 Socket Functions
- *
- * SQUID Web Proxy Cache http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- * Squid is the result of efforts by numerous individuals from
- * the Internet community; see the CONTRIBUTORS file for full
- * details. Many organizations have provided support for Squid's
- * development; see the SPONSORS file for full details. Squid is
- * Copyrighted (C) 2001 by the Regents of the University of
- * California; see the COPYRIGHT file for full details. Squid
- * incorporates software developed and/or copyrighted by other
- * sources; see the CREDITS file for full details.
- *
- * 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 2 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
*
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
*/
-#include "config.h"
-#if USE_POLL
+/* DEBUG: section 05 Socket Functions */
#include "squid.h"
+
+#if USE_POLL
+#include "anyp/PortCfg.h"
#include "comm/Connection.h"
#include "comm/Loops.h"
+#include "fd.h"
#include "fde.h"
+#include "globals.h"
#include "ICP.h"
#include "mgr/Registration.h"
+#include "profiler/Profiler.h"
+#include "SquidConfig.h"
#include "SquidTime.h"
+#include "StatCounters.h"
#include "Store.h"
+#include <cerrno>
#if HAVE_POLL_H
#include <poll.h>
#endif
#endif
#endif
-static int MAX_POLL_TIME = 1000; /* see also Comm::QuickPollRequired() */
+static int MAX_POLL_TIME = 1000; /* see also Comm::QuickPollRequired() */
#ifndef howmany
#define howmany(x, y) (((x)+((y)-1))/(y))
#define FD_MASK_BITS (FD_MASK_BYTES*NBBY)
/* STATIC */
-static int fdIsHttp(int fd);
-static int fdIsIcp(int fd);
+static int fdIsTcpListen(int fd);
+static int fdIsUdpListen(int fd);
static int fdIsDns(int fd);
static OBJH commIncomingStats;
static int comm_check_incoming_poll_handlers(int nfds, int *fds);
* multipled by a factor of (2^INCOMING_FACTOR) to have some
* pseudo-floating point precision.
*
- * The variable 'icp_io_events' and 'http_io_events' counts how many normal
+ * The variable 'udp_io_events' and 'tcp_io_events' counts how many normal
* I/O events have been processed since the last check on the incoming
* sockets. When io_events > incoming_interval, its time to check incoming
* sockets.
*
* incoming_interval = incoming_interval + target_average - number_of_events_processed
*
- * There are separate incoming_interval counters for both HTTP and ICP events
+ * There are separate incoming_interval counters for TCP-based, UDP-based, and DNS events
*
* You can see the current values of the incoming_interval's, as well as
* a histogram of 'incoming_events' by asking the cache manager
#define MAX_INCOMING_INTEGER 256
#define INCOMING_FACTOR 5
#define MAX_INCOMING_INTERVAL (MAX_INCOMING_INTEGER << INCOMING_FACTOR)
-static int icp_io_events = 0;
-static int dns_io_events = 0;
-static int http_io_events = 0;
-static int incoming_icp_interval = 16 << INCOMING_FACTOR;
+static int udp_io_events = 0; ///< I/O events passed since last UDP receiver socket poll
+static int dns_io_events = 0; ///< I/O events passed since last DNS socket poll
+static int tcp_io_events = 0; ///< I/O events passed since last TCP listening socket poll
+static int incoming_udp_interval = 16 << INCOMING_FACTOR;
static int incoming_dns_interval = 16 << INCOMING_FACTOR;
-static int incoming_http_interval = 16 << INCOMING_FACTOR;
-#define commCheckICPIncoming (++icp_io_events > (incoming_icp_interval>> INCOMING_FACTOR))
-#define commCheckDNSIncoming (++dns_io_events > (incoming_dns_interval>> INCOMING_FACTOR))
-#define commCheckHTTPIncoming (++http_io_events > (incoming_http_interval>> INCOMING_FACTOR))
-
+static int incoming_tcp_interval = 16 << INCOMING_FACTOR;
+#define commCheckUdpIncoming (++udp_io_events > (incoming_udp_interval>> INCOMING_FACTOR))
+#define commCheckDnsIncoming (++dns_io_events > (incoming_dns_interval>> INCOMING_FACTOR))
+#define commCheckTcpIncoming (++tcp_io_events > (incoming_tcp_interval>> INCOMING_FACTOR))
void
Comm::SetSelect(int fd, unsigned int type, PF * handler, void *client_data, time_t timeout)
fde *F = &fd_table[fd];
assert(fd >= 0);
assert(F->flags.open);
- debugs(5, 5, "commSetSelect: FD " << fd << " type " << type);
+ debugs(5, 5, HERE << "FD " << fd << ", type=" << type <<
+ ", handler=" << handler << ", client_data=" << client_data <<
+ ", timeout=" << timeout);
if (type & COMM_SELECT_READ) {
F->read_handler = handler;
}
static int
-fdIsIcp(int fd)
+fdIsUdpListen(int fd)
{
if (icpIncomingConn != NULL && icpIncomingConn->fd == fd)
return 1;
}
static int
-fdIsHttp(int fd)
+fdIsTcpListen(int fd)
{
- int j;
-
- for (j = 0; j < NHttpSockets; j++) {
- if (fd == HttpSockets[j])
+ for (AnyP::PortCfgPointer s = HttpPortList; s != NULL; s = s->next) {
+ if (s->listenConn != NULL && s->listenConn->fd == fd)
return 1;
}
PF *hdl = NULL;
int npfds;
- struct pollfd pfds[3 + MAXHTTPPORTS];
+ struct pollfd pfds[3 + MAXTCPLISTENPORTS];
PROF_start(comm_check_incoming);
incoming_sockets_accepted = 0;
- for (i = npfds = 0; i < nfds; i++) {
+ for (i = npfds = 0; i < nfds; ++i) {
int events;
fd = fds[i];
events = 0;
pfds[npfds].fd = fd;
pfds[npfds].events = events;
pfds[npfds].revents = 0;
- npfds++;
+ ++npfds;
}
}
}
getCurrentTime();
- statCounter.syscalls.selects++;
+ ++ statCounter.syscalls.selects;
if (poll(pfds, npfds, 0) < 1) {
PROF_stop(comm_check_incoming);
return incoming_sockets_accepted;
}
- for (i = 0; i < npfds; i++) {
+ for (i = 0; i < npfds; ++i) {
int revents;
if (((revents = pfds[i].revents) == 0) || ((fd = pfds[i].fd) == -1))
fd_table[fd].read_handler = NULL;
hdl(fd, fd_table[fd].read_data);
} else if (pfds[i].events & POLLRDNORM)
- debugs(5, 1, "comm_poll_incoming: FD " << fd << " NULL read handler");
+ debugs(5, DBG_IMPORTANT, "comm_poll_incoming: FD " << fd << " NULL read handler");
}
if (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) {
fd_table[fd].write_handler = NULL;
hdl(fd, fd_table[fd].write_data);
} else if (pfds[i].events & POLLWRNORM)
- debugs(5, 1, "comm_poll_incoming: FD " << fd << " NULL write_handler");
+ debugs(5, DBG_IMPORTANT, "comm_poll_incoming: FD " << fd << " NULL write_handler");
}
}
}
static void
-comm_poll_icp_incoming(void)
+comm_poll_udp_incoming(void)
{
int nfds = 0;
int fds[2];
int nevents;
- icp_io_events = 0;
+ udp_io_events = 0;
- if (Comm::IsConnOpen(icpIncomingConn))
- fds[nfds++] = icpIncomingConn->fd;
+ if (Comm::IsConnOpen(icpIncomingConn)) {
+ fds[nfds] = icpIncomingConn->fd;
+ ++nfds;
+ }
- if (icpIncomingConn != icpOutgoingConn && Comm::IsConnOpen(icpOutgoingConn))
- fds[nfds++] = icpOutgoingConn->fd;
+ if (icpIncomingConn != icpOutgoingConn && Comm::IsConnOpen(icpOutgoingConn)) {
+ fds[nfds] = icpOutgoingConn->fd;
+ ++nfds;
+ }
if (nfds == 0)
return;
nevents = comm_check_incoming_poll_handlers(nfds, fds);
- incoming_icp_interval += Config.comm_incoming.icp_average - nevents;
+ incoming_udp_interval += Config.comm_incoming.udp.average - nevents;
- if (incoming_icp_interval < Config.comm_incoming.icp_min_poll)
- incoming_icp_interval = Config.comm_incoming.icp_min_poll;
+ if (incoming_udp_interval < Config.comm_incoming.udp.min_poll)
+ incoming_udp_interval = Config.comm_incoming.udp.min_poll;
- if (incoming_icp_interval > MAX_INCOMING_INTERVAL)
- incoming_icp_interval = MAX_INCOMING_INTERVAL;
+ if (incoming_udp_interval > MAX_INCOMING_INTERVAL)
+ incoming_udp_interval = MAX_INCOMING_INTERVAL;
- if (nevents > INCOMING_ICP_MAX)
- nevents = INCOMING_ICP_MAX;
+ if (nevents > INCOMING_UDP_MAX)
+ nevents = INCOMING_UDP_MAX;
- statHistCount(&statCounter.comm_icp_incoming, nevents);
+ statCounter.comm_udp_incoming.count(nevents);
}
static void
-comm_poll_http_incoming(void)
+comm_poll_tcp_incoming(void)
{
int nfds = 0;
- int fds[MAXHTTPPORTS];
+ int fds[MAXTCPLISTENPORTS];
int j;
int nevents;
- http_io_events = 0;
+ tcp_io_events = 0;
- /* only poll sockets that won't be deferred */
+ // XXX: only poll sockets that won't be deferred. But how do we identify them?
- for (j = 0; j < NHttpSockets; j++) {
+ for (j = 0; j < NHttpSockets; ++j) {
if (HttpSockets[j] < 0)
continue;
- fds[nfds++] = HttpSockets[j];
+ fds[nfds] = HttpSockets[j];
+ ++nfds;
}
nevents = comm_check_incoming_poll_handlers(nfds, fds);
- incoming_http_interval = incoming_http_interval
- + Config.comm_incoming.http_average - nevents;
+ incoming_tcp_interval = incoming_tcp_interval
+ + Config.comm_incoming.tcp.average - nevents;
- if (incoming_http_interval < Config.comm_incoming.http_min_poll)
- incoming_http_interval = Config.comm_incoming.http_min_poll;
+ if (incoming_tcp_interval < Config.comm_incoming.tcp.min_poll)
+ incoming_tcp_interval = Config.comm_incoming.tcp.min_poll;
- if (incoming_http_interval > MAX_INCOMING_INTERVAL)
- incoming_http_interval = MAX_INCOMING_INTERVAL;
+ if (incoming_tcp_interval > MAX_INCOMING_INTERVAL)
+ incoming_tcp_interval = MAX_INCOMING_INTERVAL;
- if (nevents > INCOMING_HTTP_MAX)
- nevents = INCOMING_HTTP_MAX;
+ if (nevents > INCOMING_TCP_MAX)
+ nevents = INCOMING_TCP_MAX;
- statHistCount(&statCounter.comm_http_incoming, nevents);
+ statCounter.comm_tcp_incoming.count(nevents);
}
/* poll all sockets; call handlers for those that are ready. */
-comm_err_t
+Comm::Flag
Comm::DoSelect(int msec)
{
struct pollfd pfds[SQUID_MAXFD];
unsigned long nfds;
unsigned long npending;
int num;
- int callicp = 0, callhttp = 0;
- int calldns = 0;
+ int calldns = 0, calludp = 0, calltcp = 0;
double timeout = current_dtime + (msec / 1000.0);
do {
getCurrentTime();
start = current_dtime;
- if (commCheckICPIncoming)
- comm_poll_icp_incoming();
+ if (commCheckUdpIncoming)
+ comm_poll_udp_incoming();
- if (commCheckDNSIncoming)
+ if (commCheckDnsIncoming)
comm_poll_dns_incoming();
- if (commCheckHTTPIncoming)
- comm_poll_http_incoming();
+ if (commCheckTcpIncoming)
+ comm_poll_tcp_incoming();
PROF_start(comm_poll_prep_pfds);
- callicp = calldns = callhttp = 0;
+ calldns = calludp = calltcp = 0;
nfds = 0;
maxfd = Biggest_FD + 1;
- for (int i = 0; i < maxfd; i++) {
+ for (int i = 0; i < maxfd; ++i) {
int events;
events = 0;
/* Check each open socket for a handler. */
pfds[nfds].fd = i;
pfds[nfds].events = events;
pfds[nfds].revents = 0;
- nfds++;
+ ++nfds;
if ((events & POLLRDNORM) && fd_table[i].flags.read_pending)
- npending++;
+ ++npending;
}
}
*/
if (nfds == 0 && npending == 0) {
if (shutting_down)
- return COMM_SHUTDOWN;
+ return Comm::SHUTDOWN;
else
- return COMM_IDLE;
+ return Comm::IDLE;
}
for (;;) {
PROF_start(comm_poll_normal);
- ++statCounter.syscalls.selects;
+ ++ statCounter.syscalls.selects;
num = poll(pfds, nfds, msec);
- ++statCounter.select_loops;
+ int xerrno = errno;
+ ++ statCounter.select_loops;
PROF_stop(comm_poll_normal);
if (num >= 0 || npending > 0)
break;
- if (ignoreErrno(errno))
+ if (ignoreErrno(xerrno))
continue;
- debugs(5, 0, "comm_poll: poll failure: " << xstrerror());
+ debugs(5, DBG_CRITICAL, MYNAME << "poll failure: " << xstrerr(xerrno));
- assert(errno != EINVAL);
+ assert(xerrno != EINVAL);
- return COMM_ERROR;
+ return Comm::COMM_ERROR;
/* NOTREACHED */
}
getCurrentTime();
debugs(5, num ? 5 : 8, "comm_poll: " << num << "+" << npending << " FDs ready");
- statHistCount(&statCounter.select_fds_hist, num);
+ statCounter.select_fds_hist.count(num);
if (num == 0 && npending == 0)
continue;
* limit in SunOS */
PROF_start(comm_handle_ready_fd);
- for (size_t loopIndex = 0; loopIndex < nfds; loopIndex++) {
+ for (size_t loopIndex = 0; loopIndex < nfds; ++loopIndex) {
fde *F;
int revents = pfds[loopIndex].revents;
fd = pfds[loopIndex].fd;
if (revents == 0)
continue;
- if (fdIsIcp(fd)) {
- callicp = 1;
+ if (fdIsUdpListen(fd)) {
+ calludp = 1;
continue;
}
continue;
}
- if (fdIsHttp(fd)) {
- callhttp = 1;
+ if (fdIsTcpListen(fd)) {
+ calltcp = 1;
continue;
}
if (revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) {
debugs(5, 6, "comm_poll: FD " << fd << " ready for reading");
- if (NULL == (hdl = F->read_handler))
- (void) 0;
- else {
+ if ((hdl = F->read_handler)) {
PROF_start(comm_read_handler);
F->read_handler = NULL;
- F->flags.read_pending = 0;
+ F->flags.read_pending = false;
hdl(fd, F->read_data);
PROF_stop(comm_read_handler);
- statCounter.select_fds++;
+ ++ statCounter.select_fds;
- if (commCheckICPIncoming)
- comm_poll_icp_incoming();
+ if (commCheckUdpIncoming)
+ comm_poll_udp_incoming();
- if (commCheckDNSIncoming)
+ if (commCheckDnsIncoming)
comm_poll_dns_incoming();
- if (commCheckHTTPIncoming)
- comm_poll_http_incoming();
+ if (commCheckTcpIncoming)
+ comm_poll_tcp_incoming();
}
}
if (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) {
- debugs(5, 5, "comm_poll: FD " << fd << " ready for writing");
+ debugs(5, 6, "comm_poll: FD " << fd << " ready for writing");
if ((hdl = F->write_handler)) {
PROF_start(comm_write_handler);
F->write_handler = NULL;
hdl(fd, F->write_data);
PROF_stop(comm_write_handler);
- statCounter.select_fds++;
+ ++ statCounter.select_fds;
- if (commCheckICPIncoming)
- comm_poll_icp_incoming();
+ if (commCheckUdpIncoming)
+ comm_poll_udp_incoming();
- if (commCheckDNSIncoming)
+ if (commCheckDnsIncoming)
comm_poll_dns_incoming();
- if (commCheckHTTPIncoming)
- comm_poll_http_incoming();
+ if (commCheckTcpIncoming)
+ comm_poll_tcp_incoming();
}
}
if (revents & POLLNVAL) {
AsyncCall::Pointer ch;
- debugs(5, 0, "WARNING: FD " << fd << " has handlers, but it's invalid.");
- debugs(5, 0, "FD " << fd << " is a " << fdTypeStr[F->type]);
- debugs(5, 0, "--> " << F->desc);
- debugs(5, 0, "tmout:" << F->timeoutHandler << "read:" <<
+ debugs(5, DBG_CRITICAL, "WARNING: FD " << fd << " has handlers, but it's invalid.");
+ debugs(5, DBG_CRITICAL, "FD " << fd << " is a " << fdTypeStr[F->type]);
+ debugs(5, DBG_CRITICAL, "--> " << F->desc);
+ debugs(5, DBG_CRITICAL, "tmout:" << F->timeoutHandler << "read:" <<
F->read_handler << " write:" << F->write_handler);
for (ch = F->closeHandler; ch != NULL; ch = ch->Next())
- debugs(5, 0, " close handler: " << ch);
+ debugs(5, DBG_CRITICAL, " close handler: " << ch);
if (F->closeHandler != NULL) {
commCallCloseHandlers(fd);
} else if (F->timeoutHandler != NULL) {
- debugs(5, 0, "comm_poll: Calling Timeout Handler");
+ debugs(5, DBG_CRITICAL, "comm_poll: Calling Timeout Handler");
ScheduleCallHere(F->timeoutHandler);
}
PROF_stop(comm_handle_ready_fd);
- if (callicp)
- comm_poll_icp_incoming();
+ if (calludp)
+ comm_poll_udp_incoming();
if (calldns)
comm_poll_dns_incoming();
- if (callhttp)
- comm_poll_http_incoming();
+ if (calltcp)
+ comm_poll_tcp_incoming();
getCurrentTime();
statCounter.select_time += (current_dtime - start);
- return COMM_OK;
+ return Comm::OK;
} while (timeout > current_dtime);
debugs(5, 8, "comm_poll: time out: " << squid_curtime << ".");
- return COMM_TIMEOUT;
+ return Comm::TIMEOUT;
}
-
static void
comm_poll_dns_incoming(void)
{
if (DnsSocketA < 0 && DnsSocketB < 0)
return;
- if (DnsSocketA >= 0)
- fds[nfds++] = DnsSocketA;
+ if (DnsSocketA >= 0) {
+ fds[nfds] = DnsSocketA;
+ ++nfds;
+ }
- if (DnsSocketB >= 0)
- fds[nfds++] = DnsSocketB;
+ if (DnsSocketB >= 0) {
+ fds[nfds] = DnsSocketB;
+ ++nfds;
+ }
nevents = comm_check_incoming_poll_handlers(nfds, fds);
if (nevents < 0)
return;
- incoming_dns_interval += Config.comm_incoming.dns_average - nevents;
+ incoming_dns_interval += Config.comm_incoming.dns.average - nevents;
- if (incoming_dns_interval < Config.comm_incoming.dns_min_poll)
- incoming_dns_interval = Config.comm_incoming.dns_min_poll;
+ if (incoming_dns_interval < Config.comm_incoming.dns.min_poll)
+ incoming_dns_interval = Config.comm_incoming.dns.min_poll;
if (incoming_dns_interval > MAX_INCOMING_INTERVAL)
incoming_dns_interval = MAX_INCOMING_INTERVAL;
if (nevents > INCOMING_DNS_MAX)
nevents = INCOMING_DNS_MAX;
- statHistCount(&statCounter.comm_dns_incoming, nevents);
+ statCounter.comm_dns_incoming.count(nevents);
}
-
static void
commPollRegisterWithCacheManager(void)
{
static void
commIncomingStats(StoreEntry * sentry)
{
- StatCounters *f = &statCounter;
- storeAppendPrintf(sentry, "Current incoming_icp_interval: %d\n",
- incoming_icp_interval >> INCOMING_FACTOR);
+ storeAppendPrintf(sentry, "Current incoming_udp_interval: %d\n",
+ incoming_udp_interval >> INCOMING_FACTOR);
storeAppendPrintf(sentry, "Current incoming_dns_interval: %d\n",
incoming_dns_interval >> INCOMING_FACTOR);
- storeAppendPrintf(sentry, "Current incoming_http_interval: %d\n",
- incoming_http_interval >> INCOMING_FACTOR);
+ storeAppendPrintf(sentry, "Current incoming_tcp_interval: %d\n",
+ incoming_tcp_interval >> INCOMING_FACTOR);
storeAppendPrintf(sentry, "\n");
storeAppendPrintf(sentry, "Histogram of events per incoming socket type\n");
- storeAppendPrintf(sentry, "ICP Messages handled per comm_poll_icp_incoming() call:\n");
- statHistDump(&f->comm_icp_incoming, sentry, statHistIntDumper);
+ storeAppendPrintf(sentry, "ICP Messages handled per comm_poll_udp_incoming() call:\n");
+ statCounter.comm_udp_incoming.dump(sentry, statHistIntDumper);
storeAppendPrintf(sentry, "DNS Messages handled per comm_poll_dns_incoming() call:\n");
- statHistDump(&f->comm_dns_incoming, sentry, statHistIntDumper);
- storeAppendPrintf(sentry, "HTTP Messages handled per comm_poll_http_incoming() call:\n");
- statHistDump(&f->comm_http_incoming, sentry, statHistIntDumper);
+ statCounter.comm_dns_incoming.dump(sentry, statHistIntDumper);
+ storeAppendPrintf(sentry, "HTTP Messages handled per comm_poll_tcp_incoming() call:\n");
+ statCounter.comm_tcp_incoming.dump(sentry, statHistIntDumper);
}
/* Called by async-io or diskd to speed up the polling */
}
#endif /* USE_POLL */
+