TcpAcceptor.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2019 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* DEBUG: section 05 Listener Socket Handler */
10 
11 #include "squid.h"
12 #include "acl/FilledChecklist.h"
13 #include "anyp/PortCfg.h"
14 #include "base/TextException.h"
15 #include "client_db.h"
16 #include "comm/AcceptLimiter.h"
17 #include "comm/comm_internal.h"
18 #include "comm/Connection.h"
19 #include "comm/Loops.h"
20 #include "comm/TcpAcceptor.h"
21 #include "CommCalls.h"
22 #include "eui/Config.h"
23 #include "fd.h"
24 #include "fde.h"
25 #include "globals.h"
26 #include "ip/Intercept.h"
27 #include "ip/QosConfig.h"
28 #include "log/access_log.h"
29 #include "MasterXaction.h"
30 #include "profiler/Profiler.h"
31 #include "SquidConfig.h"
32 #include "SquidTime.h"
33 #include "StatCounters.h"
34 
35 #include <cerrno>
36 #ifdef HAVE_NETINET_TCP_H
37 // required for accept_filter to build.
38 #include <netinet/tcp.h>
39 #endif
40 
42 
44  AsyncJob("Comm::TcpAcceptor"),
45  errcode(0),
46  theCallSub(aSub),
47  conn(newConn),
48  listenPort_()
49 {}
50 
52  AsyncJob("Comm::TcpAcceptor"),
53  errcode(0),
54  theCallSub(aSub),
55  conn(p->listenConn),
56  listenPort_(p)
57 {}
58 
59 void
61 {
62  debugs(5, 5, HERE << status() << " AsyncCall Subscription: " << aSub);
63  unsubscribe("subscription change");
64  theCallSub = aSub;
65 }
66 
67 void
68 Comm::TcpAcceptor::unsubscribe(const char *reason)
69 {
70  debugs(5, 5, HERE << status() << " AsyncCall Subscription " << theCallSub << " removed: " << reason);
71  theCallSub = NULL;
72 }
73 
74 void
76 {
77  debugs(5, 5, HERE << status() << " AsyncCall Subscription: " << theCallSub);
78 
80 
81  setListen();
82 
83  conn->noteStart();
84 
85  // if no error so far start accepting connections.
86  if (errcode == 0)
88 }
89 
90 bool
92 {
93  // stop when FD is closed
94  if (!IsConnOpen(conn)) {
95  return AsyncJob::doneAll();
96  }
97 
98  // stop when handlers are gone
99  if (theCallSub == NULL) {
100  return AsyncJob::doneAll();
101  }
102 
103  // open FD with handlers...keep accepting.
104  return false;
105 }
106 
107 void
109 {
110  debugs(5,5, HERE);
111  unsubscribe("swanSong");
112  if (IsConnOpen(conn)) {
113  if (closer_ != NULL)
115  conn->close();
116  }
117 
118  conn = NULL;
121 }
122 
123 const char *
125 {
126  if (conn == NULL)
127  return "[nil connection]";
128 
129  static char ipbuf[MAX_IPSTRLEN] = {'\0'};
130  if (ipbuf[0] == '\0')
131  conn->local.toHostStr(ipbuf, MAX_IPSTRLEN);
132 
133  static MemBuf buf;
134  buf.reset();
135  buf.appendf(" FD %d, %s",conn->fd, ipbuf);
136 
137  const char *jobStatus = AsyncJob::status();
138  buf.append(jobStatus, strlen(jobStatus));
139 
140  return buf.content();
141 }
142 
150 void
152 {
153  errcode = errno = 0;
154  if (listen(conn->fd, Squid_MaxFD >> 2) < 0) {
155  errcode = errno;
156  debugs(50, DBG_CRITICAL, "ERROR: listen(" << status() << ", " << (Squid_MaxFD >> 2) << "): " << xstrerr(errcode));
157  return;
158  }
159 
160  if (Config.accept_filter && strcmp(Config.accept_filter, "none") != 0) {
161 #ifdef SO_ACCEPTFILTER
162  struct accept_filter_arg afa;
163  bzero(&afa, sizeof(afa));
164  debugs(5, DBG_IMPORTANT, "Installing accept filter '" << Config.accept_filter << "' on " << conn);
165  xstrncpy(afa.af_name, Config.accept_filter, sizeof(afa.af_name));
166  if (setsockopt(conn->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
167  int xerrno = errno;
168  debugs(5, DBG_CRITICAL, "WARNING: SO_ACCEPTFILTER '" << Config.accept_filter << "': '" << xstrerr(xerrno));
169  }
170 #elif defined(TCP_DEFER_ACCEPT)
171  int seconds = 30;
172  if (strncmp(Config.accept_filter, "data=", 5) == 0)
173  seconds = atoi(Config.accept_filter + 5);
174  if (setsockopt(conn->fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &seconds, sizeof(seconds)) < 0) {
175  int xerrno = errno;
176  debugs(5, DBG_CRITICAL, "WARNING: TCP_DEFER_ACCEPT '" << Config.accept_filter << "': '" << xstrerr(xerrno));
177  }
178 #else
179  debugs(5, DBG_CRITICAL, "WARNING: accept_filter not supported on your OS");
180 #endif
181  }
182 
183 #if 0
184  // Untested code.
185  // Set TOS if needed.
186  // To correctly implement TOS values on listening sockets, probably requires
187  // more work to inherit TOS values to created connection objects.
188  if (conn->tos)
190 #if SO_MARK
191  if (conn->nfmark)
193 #endif
194 #endif
195 
199 }
200 
203 void
205 {
206  closer_ = NULL;
207  conn = NULL;
208  Must(done());
209 }
210 
220 void
222 {
223  try {
224  debugs(5, 2, HERE << "New connection on FD " << fd);
225 
226  Must(isOpen(fd));
227  TcpAcceptor *afd = static_cast<TcpAcceptor*>(data);
228 
229  if (!okToAccept()) {
231  } else {
232  afd->acceptNext();
233  }
234 
235  } catch (const std::exception &e) {
236  fatalf("FATAL: error while accepting new client connection: %s\n", e.what());
237  } catch (...) {
238  fatal("FATAL: error while accepting new client connection: [unknown]\n");
239  }
240 }
241 
242 bool
244 {
245  static time_t last_warn = 0;
246 
247  if (fdNFree() >= RESERVED_FD)
248  return true;
249 
250  if (last_warn + 15 < squid_curtime) {
251  debugs(5, DBG_CRITICAL, "WARNING! Your cache is running out of filedescriptors");
252  last_warn = squid_curtime;
253  }
254 
255  return false;
256 }
257 
258 static void
260 {
262  al->tcpClient = conn;
263  al->url = "error:accept-client-connection";
264  al->setVirginUrlForMissingRequest(al->url);
265  ACLFilledChecklist ch(nullptr, nullptr, nullptr);
266  ch.src_addr = conn->remote;
267  ch.my_addr = conn->local;
268  ch.al = al;
269  accessLogLog(al, &ch);
270 }
271 
272 void
274 {
275  /*
276  * We don't worry about running low on FDs here. Instead,
277  * doAccept() will use AcceptLimiter if we reach the limit
278  * there.
279  */
280 
281  /* Accept a new connection */
282  ConnectionPointer newConnDetails = new Connection();
283  const Comm::Flag flag = oldAccept(newConnDetails);
284 
285  if (flag == Comm::COMM_ERROR) {
286  // A non-recoverable error; notify the caller */
287  debugs(5, 5, HERE << "non-recoverable error:" << status() << " handler Subscription: " << theCallSub);
289  logAcceptError(newConnDetails);
290  notify(flag, newConnDetails);
291  mustStop("Listener socket closed");
292  return;
293  }
294 
295  if (flag == Comm::NOMESSAGE) {
296  /* register interest again */
297  debugs(5, 5, "try later: " << conn << " handler Subscription: " << theCallSub);
298  } else {
299  debugs(5, 5, "Listener: " << conn <<
300  " accepted new connection " << newConnDetails <<
301  " handler Subscription: " << theCallSub);
302  notify(flag, newConnDetails);
303  }
304 
306 }
307 
308 void
310 {
311  Must(IsConnOpen(conn));
312  debugs(5, 2, HERE << "connection on " << conn);
313  acceptOne();
314 }
315 
316 void
317 Comm::TcpAcceptor::notify(const Comm::Flag flag, const Comm::ConnectionPointer &newConnDetails) const
318 {
319  // listener socket handlers just abandon the port with Comm::ERR_CLOSING
320  // it should only happen when this object is deleted...
321  if (flag == Comm::ERR_CLOSING) {
322  return;
323  }
324 
325  if (theCallSub != NULL) {
327  CommAcceptCbParams &params = GetCommParams<CommAcceptCbParams>(call);
329  params.xaction->squidPort = listenPort_;
330  params.fd = conn->fd;
331  params.conn = params.xaction->tcpClient = newConnDetails;
332  params.flag = flag;
333  params.xerrno = errcode;
334  ScheduleCallHere(call);
335  }
336 }
337 
349 {
350  PROF_start(comm_accept);
351  ++statCounter.syscalls.sock.accepts;
352  int sock;
353  struct addrinfo *gai = NULL;
355 
356  errcode = 0; // reset local errno copy.
357  if ((sock = accept(conn->fd, gai->ai_addr, &gai->ai_addrlen)) < 0) {
358  errcode = errno; // store last accept errno locally.
359 
361 
362  PROF_stop(comm_accept);
363 
364  if (ignoreErrno(errcode) || errcode == ECONNABORTED) {
365  debugs(50, 5, status() << ": " << xstrerr(errcode));
366  return Comm::NOMESSAGE;
367  } else if (errcode == ENFILE || errcode == EMFILE) {
368  debugs(50, 3, status() << ": " << xstrerr(errcode));
369  return Comm::COMM_ERROR;
370  } else {
371  debugs(50, DBG_IMPORTANT, MYNAME << status() << ": " << xstrerr(errcode));
372  return Comm::COMM_ERROR;
373  }
374  }
375 
376  Must(sock >= 0);
377  details->fd = sock;
378  details->remote = *gai;
379 
380  // lookup the local-end details of this new connection
382  details->local.setEmpty();
383  if (getsockname(sock, gai->ai_addr, &gai->ai_addrlen) != 0) {
384  int xerrno = errno;
385  debugs(50, DBG_IMPORTANT, "ERROR: getsockname() failed to locate local-IP on " << details << ": " << xstrerr(xerrno));
387  PROF_stop(comm_accept);
388  return Comm::COMM_ERROR;
389  }
390  details->local = *gai;
392 
393  // Perform NAT or TPROXY operations to retrieve the real client/dest IP addresses
395  debugs(50, DBG_IMPORTANT, "ERROR: NAT/TPROXY lookup failed to locate original IPs on " << details);
396  // Failed.
397  PROF_stop(comm_accept);
398  return Comm::COMM_ERROR;
399  }
400 
401 #if USE_SQUID_EUI
402  if (Eui::TheConfig.euiLookup) {
403  if (details->remote.isIPv4()) {
404  details->remoteEui48.lookup(details->remote);
405  } else if (details->remote.isIPv6()) {
406  details->remoteEui64.lookup(details->remote);
407  }
408  }
409 #endif
410 
412 
415  debugs(50, DBG_IMPORTANT, "WARNING: " << details->remote << " attempting more than " << Config.client_ip_max_connections << " connections.");
416  PROF_stop(comm_accept);
417  return Comm::NOMESSAGE;
418  }
419  }
420 
421  /* fdstat update */
422  // XXX : these are not all HTTP requests. use a note about type and ip:port details->
423  // so we end up with a uniform "(HTTP|FTP-data|HTTPS|...) remote-ip:remote-port"
424  fd_open(sock, FD_SOCKET, "HTTP Request");
425 
426  fde *F = &fd_table[sock];
427  details->remote.toStr(F->ipaddr,MAX_IPSTRLEN);
428  F->remote_port = details->remote.port();
429  F->local_addr = details->local;
430  F->sock_family = details->local.isIPv6()?AF_INET6:AF_INET;
431 
432  // set socket flags
433  commSetCloseOnExec(sock);
434  commSetNonBlocking(sock);
435 
436  /* IFF the socket is (tproxy) transparent, pass the flag down to allow spoofing */
437  F->flags.transparent = fd_table[conn->fd].flags.transparent; // XXX: can we remove this line yet?
438 
439  PROF_stop(comm_accept);
440  return Comm::OK;
441 }
442 
AnyP::PortCfgPointer squidPort
the listening port which originated this transaction
Definition: MasterXaction.h:50
bool Lookup(const Comm::ConnectionPointer &newConn, const Comm::ConnectionPointer &listenConn)
Definition: Intercept.cc:389
#define JobCallback(dbgSection, dbgLevel, Dialer, job, method)
Convenience macro to create a Dialer-based job callback.
Definition: AsyncJobCalls.h:68
#define fd_table
Definition: fde.h:157
#define COMM_SELECT_READ
Definition: defines.h:36
unsigned short port() const
Definition: Address.cc:778
StatCounters statCounter
Definition: StatCounters.cc:12
bool isOpen(const int fd)
Definition: comm.cc:86
void unsubscribe(const char *reason)
Definition: TcpAcceptor.cc:68
int Squid_MaxFD
virtual void append(const char *c, int sz)
Definition: MemBuf.cc:216
struct fde::_fde_flags flags
nfmark_t nfmark
Definition: Connection.h:152
static void FreeAddr(struct addrinfo *&ai)
Definition: Address.cc:686
Ip::Address local_addr
Definition: fde.h:86
void accessLogLog(AccessLogEntry::Pointer &, ACLChecklist *checklist)
Definition: access_log.cc:144
virtual AsyncCall::Pointer callback() const =0
Abstraction layer for TCP, UDP, TLS, UDS and filedescriptor sockets.
Definition: AcceptLimiter.h:16
unsigned short remote_port
Definition: fde.h:84
void mustStop(const char *aReason)
Definition: AsyncJob.cc:69
static void doAccept(int fd, void *data)
Method callback for whenever an FD is ready to accept a client connection.
Definition: TcpAcceptor.cc:221
int client_ip_max_connections
Definition: SquidConfig.h:532
ConnectionPointer conn
Definition: TcpAcceptor.h:91
Ip::Address src_addr
bool intendedForUserConnections() const
whether we are listening on one of the squid.conf *ports
Definition: TcpAcceptor.h:107
int clientdbEstablished(const Ip::Address &addr, int delta)
Definition: client_db.cc:183
void fd_open(int fd, unsigned int type, const char *desc)
Definition: fd.cc:186
Definition: Flag.h:16
AccessLogEntry::Pointer al
info for the future access.log, and external ACL
AnyP::PortCfgPointer listenPort_
configuration details of the listening port (if provided)
Definition: TcpAcceptor.h:94
#define Must(condition)
Like assert() but throws an exception instead of aborting the process.
Definition: TextException.h:69
#define COMM_INTERCEPTION
Definition: Connection.h:49
void handleClosure(const CommCloseCbParams &io)
Definition: TcpAcceptor.cc:204
#define DBG_CRITICAL
Definition: Debug.h:45
char * p
Definition: membanger.c:43
int conn
the current server connection FD
Definition: Transport.cc:26
int fdNFree(void)
Definition: fd.cc:299
Eui::Eui64 remoteEui64
Definition: Connection.h:169
time_t squid_curtime
Definition: stub_time.cc:17
nfmark_t nfConnmark
Definition: Connection.h:160
Eui::Eui48 remoteEui48
Definition: Connection.h:168
int sock_family
Definition: fde.h:91
void fatalf(const char *fmt,...)
Definition: fatal.cc:68
virtual const char * status() const
internal cleanup; do not call directly
Definition: AsyncJob.cc:159
bool isIPv4() const
Definition: Address.cc:158
int RESERVED_FD
struct StatCounters::@135::@139 sock
Comm::ConnectionPointer conn
Definition: CommCalls.h:85
const char * xstrerr(int error)
Definition: xstrerror.cc:83
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition: Connection.cc:24
void const char HLPCB void * data
Definition: stub_helper.cc:16
nfmark_t getNfConnmark(const Comm::ConnectionPointer &conn, const ConnectionDirection connDir)
Definition: QosConfig.cc:141
int fd
FD which the call was about. Set by the async call creator.
Definition: CommCalls.h:90
bool lookup(const Ip::Address &c)
Definition: Eui48.cc:135
char * toStr(char *buf, const unsigned int blen, int force=AF_UNSPEC) const
Definition: Address.cc:802
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:124
#define DBG_IMPORTANT
Definition: Debug.h:46
TcpAcceptor(const TcpAcceptor &)
void SetSelect(int, unsigned int, PF *, void *, time_t)
Mark an FD to be watched for its IO status.
Definition: ModDevPoll.cc:225
virtual void swanSong()
Definition: AsyncJob.h:54
Subscription::Pointer theCallSub
used to generate AsyncCalls handling our events.
Definition: TcpAcceptor.h:87
void reset()
Definition: MemBuf.cc:132
static bool okToAccept()
Definition: TcpAcceptor.cc:243
int xerrno
The last errno to occur. non-zero if flag is Comm::COMM_ERROR.
Definition: CommCalls.h:88
static void logAcceptError(const Comm::ConnectionPointer &conn)
Definition: TcpAcceptor.cc:259
void commSetCloseOnExec(int fd)
Definition: comm.cc:1137
static void InitAddr(struct addrinfo *&ai)
Definition: Address.cc:668
char * xstrncpy(char *dst, const char *src, size_t n)
Definition: xstring.cc:37
void fatal(const char *message)
Definition: fatal.cc:28
char * accept_filter
Definition: SquidConfig.h:522
int commSetNonBlocking(int fd)
Definition: comm.cc:1076
bool isIPv6() const
Definition: Address.cc:164
struct StatCounters::@135 syscalls
void setEmpty()
Fast reset of the stored content to what would be after default constructor.
Definition: Address.cc:184
void defer(const TcpAcceptor::Pointer &afd)
virtual const char * status() const
internal cleanup; do not call directly
Definition: TcpAcceptor.cc:124
char * content()
start of the added data
Definition: MemBuf.h:41
void const char * buf
Definition: stub_helper.cc:16
std::ostream & HERE(std::ostream &s)
Definition: Debug.h:153
Flag
Definition: Flag.h:15
Ip::Address local
Definition: Connection.h:135
int ignoreErrno(int ierrno)
Definition: comm.cc:1477
EuiConfig TheConfig
Definition: Config.cc:12
void notify(const Comm::Flag flag, const Comm::ConnectionPointer &details) const
Call the subscribed callback handler with details about a new connection.
Definition: TcpAcceptor.cc:317
#define MYNAME
Definition: Debug.h:166
void removeDead(const TcpAcceptor::Pointer &afd)
Ip::Address remote
Definition: Connection.h:138
#define COMM_TRANSPARENT
Definition: Connection.h:48
Comm::Flag oldAccept(Comm::ConnectionPointer &details)
Definition: TcpAcceptor.cc:348
MasterXaction::Pointer xaction
Transaction which this call is part of.
Definition: CommCalls.h:105
#define ScheduleCallHere(call)
Definition: AsyncCall.h:166
socklen_t ai_addrlen
#define PROF_start(probename)
Definition: Profiler.h:62
AsyncCall::Pointer closer_
listen socket closure handler
Definition: TcpAcceptor.h:97
virtual bool doneAll() const
whether positive goal has been reached
Definition: AsyncJob.cc:96
Comm::Flag flag
comm layer result status.
Definition: CommCalls.h:87
CBDATA_NAMESPACED_CLASS_INIT(Comm, TcpAcceptor)
struct sockaddr * ai_addr
bool transparent
Definition: fde.h:108
void appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Append operation with printf-style arguments.
Definition: Packable.h:61
accepted (from a client by Squid)
Definition: QosConfig.h:67
Definition: fde.h:49
Definition: MemBuf.h:23
virtual bool doneAll() const
whether positive goal has been reached
Definition: TcpAcceptor.cc:91
int setSockNfmark(const Comm::ConnectionPointer &conn, nfmark_t mark)
Definition: QosConfig.cc:586
AsyncCall::Pointer comm_add_close_handler(int fd, CLCB *handler, void *data)
Definition: comm.cc:961
static uint32 F(uint32 X, uint32 Y, uint32 Z)
Definition: md4.c:46
#define MAX_IPSTRLEN
Length of buffer that needs to be allocated to old a null-terminated IP-string.
Definition: forward.h:23
bool lookup(const Ip::Address &c)
Definition: Eui64.cc:47
#define PROF_stop(probename)
Definition: Profiler.h:63
virtual void swanSong()
Definition: TcpAcceptor.cc:108
unsigned int toHostStr(char *buf, const unsigned int len) const
Definition: Address.cc:852
char ipaddr[MAX_IPSTRLEN]
Definition: fde.h:92
void subscribe(const Subscription::Pointer &aSub)
Definition: TcpAcceptor.cc:60
void comm_remove_close_handler(int fd, CLCB *handler, void *data)
Definition: comm.cc:988
static AcceptLimiter & Instance()
int setSockTos(const Comm::ConnectionPointer &conn, tos_t tos)
Definition: QosConfig.cc:558
bool done() const
the job is destroyed in callEnd() when done()
Definition: AsyncJob.cc:90
virtual void start()
called by AsyncStart; do not call directly
Definition: TcpAcceptor.cc:75
Intercept Interceptor
Definition: Intercept.h:154
Comm::ConnectionPointer tcpClient
the client TCP connection which originated this transaction
Definition: MasterXaction.h:53
class SquidConfig Config
Definition: SquidConfig.cc:12
#define NULL
Definition: types.h:166
int errcode
errno code of the last accept() or listen() action if one occurred.
Definition: TcpAcceptor.h:77

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors