]>
Commit | Line | Data |
---|---|---|
04f55905 | 1 | /* |
77b1029d | 2 | * Copyright (C) 1996-2020 The Squid Software Foundation and contributors |
04f55905 | 3 | * |
bbc27441 AJ |
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. | |
04f55905 AJ |
7 | */ |
8 | ||
bbc27441 AJ |
9 | /* DEBUG: section 05 Listener Socket Handler */ |
10 | ||
582c2af2 | 11 | #include "squid.h" |
da6dbcd1 | 12 | #include "acl/FilledChecklist.h" |
94bfd31f | 13 | #include "anyp/PortCfg.h" |
a9870624 | 14 | #include "base/TextException.h" |
95e6d864 | 15 | #include "client_db.h" |
04f55905 AJ |
16 | #include "comm/AcceptLimiter.h" |
17 | #include "comm/comm_internal.h" | |
5b67dfa4 | 18 | #include "comm/Connection.h" |
d841c88d | 19 | #include "comm/Loops.h" |
cbff89ba | 20 | #include "comm/TcpAcceptor.h" |
602d9612 | 21 | #include "CommCalls.h" |
83b62d3f | 22 | #include "eui/Config.h" |
c4ad1349 | 23 | #include "fd.h" |
04f55905 | 24 | #include "fde.h" |
67679543 | 25 | #include "globals.h" |
40d34a62 | 26 | #include "ip/Intercept.h" |
c6f168c1 | 27 | #include "ip/QosConfig.h" |
da6dbcd1 | 28 | #include "log/access_log.h" |
94bfd31f | 29 | #include "MasterXaction.h" |
582c2af2 | 30 | #include "profiler/Profiler.h" |
4d5904f7 | 31 | #include "SquidConfig.h" |
04f55905 | 32 | #include "SquidTime.h" |
e4f1fdae | 33 | #include "StatCounters.h" |
04f55905 | 34 | |
1a30fdf5 | 35 | #include <cerrno> |
f842580f AJ |
36 | #ifdef HAVE_NETINET_TCP_H |
37 | // required for accept_filter to build. | |
38 | #include <netinet/tcp.h> | |
39 | #endif | |
21d845b1 | 40 | |
f842580f | 41 | CBDATA_NAMESPACED_CLASS_INIT(Comm, TcpAcceptor); |
a9870624 | 42 | |
ced8def3 | 43 | Comm::TcpAcceptor::TcpAcceptor(const Comm::ConnectionPointer &newConn, const char *, const Subscription::Pointer &aSub) : |
f53969cc SM |
44 | AsyncJob("Comm::TcpAcceptor"), |
45 | errcode(0), | |
f53969cc SM |
46 | theCallSub(aSub), |
47 | conn(newConn), | |
48 | listenPort_() | |
fa720bfb AJ |
49 | {} |
50 | ||
ced8def3 | 51 | Comm::TcpAcceptor::TcpAcceptor(const AnyP::PortCfgPointer &p, const char *, const Subscription::Pointer &aSub) : |
f53969cc SM |
52 | AsyncJob("Comm::TcpAcceptor"), |
53 | errcode(0), | |
f53969cc SM |
54 | theCallSub(aSub), |
55 | conn(p->listenConn), | |
56 | listenPort_(p) | |
cbff89ba | 57 | {} |
0ba55a12 AJ |
58 | |
59 | void | |
cbff89ba | 60 | Comm::TcpAcceptor::subscribe(const Subscription::Pointer &aSub) |
0ba55a12 | 61 | { |
cbff89ba | 62 | debugs(5, 5, HERE << status() << " AsyncCall Subscription: " << aSub); |
5b67dfa4 AJ |
63 | unsubscribe("subscription change"); |
64 | theCallSub = aSub; | |
4c5518e5 AJ |
65 | } |
66 | ||
0ba55a12 | 67 | void |
cbff89ba | 68 | Comm::TcpAcceptor::unsubscribe(const char *reason) |
0ba55a12 | 69 | { |
cbff89ba | 70 | debugs(5, 5, HERE << status() << " AsyncCall Subscription " << theCallSub << " removed: " << reason); |
5b67dfa4 | 71 | theCallSub = NULL; |
0ba55a12 AJ |
72 | } |
73 | ||
a9870624 | 74 | void |
cbff89ba | 75 | Comm::TcpAcceptor::start() |
a9870624 | 76 | { |
ccfbe8f4 AR |
77 | if (listenPort_) |
78 | CodeContext::Reset(listenPort_); | |
cbff89ba | 79 | debugs(5, 5, HERE << status() << " AsyncCall Subscription: " << theCallSub); |
a9870624 AJ |
80 | |
81 | Must(IsConnOpen(conn)); | |
82 | ||
83 | setListen(); | |
84 | ||
8aec3e1b CT |
85 | conn->noteStart(); |
86 | ||
a9870624 AJ |
87 | // if no error so far start accepting connections. |
88 | if (errcode == 0) | |
8bbb16e3 | 89 | SetSelect(conn->fd, COMM_SELECT_READ, doAccept, this, 0); |
a9870624 AJ |
90 | } |
91 | ||
92 | bool | |
cbff89ba | 93 | Comm::TcpAcceptor::doneAll() const |
a9870624 | 94 | { |
6f8536c0 | 95 | // stop when FD is closed |
a9870624 | 96 | if (!IsConnOpen(conn)) { |
a9870624 AJ |
97 | return AsyncJob::doneAll(); |
98 | } | |
99 | ||
5b67dfa4 AJ |
100 | // stop when handlers are gone |
101 | if (theCallSub == NULL) { | |
a9870624 AJ |
102 | return AsyncJob::doneAll(); |
103 | } | |
104 | ||
5b67dfa4 | 105 | // open FD with handlers...keep accepting. |
a9870624 AJ |
106 | return false; |
107 | } | |
108 | ||
109 | void | |
cbff89ba | 110 | Comm::TcpAcceptor::swanSong() |
a9870624 AJ |
111 | { |
112 | debugs(5,5, HERE); | |
5b67dfa4 | 113 | unsubscribe("swanSong"); |
6f09127c AR |
114 | if (IsConnOpen(conn)) { |
115 | if (closer_ != NULL) | |
116 | comm_remove_close_handler(conn->fd, closer_); | |
117 | conn->close(); | |
118 | } | |
119 | ||
a9870624 | 120 | conn = NULL; |
5b67dfa4 | 121 | AcceptLimiter::Instance().removeDead(this); |
a9870624 AJ |
122 | AsyncJob::swanSong(); |
123 | } | |
124 | ||
cbff89ba AJ |
125 | const char * |
126 | Comm::TcpAcceptor::status() const | |
127 | { | |
8bbb16e3 AJ |
128 | if (conn == NULL) |
129 | return "[nil connection]"; | |
130 | ||
cbff89ba AJ |
131 | static char ipbuf[MAX_IPSTRLEN] = {'\0'}; |
132 | if (ipbuf[0] == '\0') | |
4dd643d5 | 133 | conn->local.toHostStr(ipbuf, MAX_IPSTRLEN); |
cbff89ba AJ |
134 | |
135 | static MemBuf buf; | |
136 | buf.reset(); | |
4391cd15 | 137 | buf.appendf(" FD %d, %s",conn->fd, ipbuf); |
cbff89ba AJ |
138 | |
139 | const char *jobStatus = AsyncJob::status(); | |
140 | buf.append(jobStatus, strlen(jobStatus)); | |
141 | ||
142 | return buf.content(); | |
143 | } | |
144 | ||
0ba55a12 AJ |
145 | /** |
146 | * New-style listen and accept routines | |
147 | * | |
148 | * setListen simply registers our interest in an FD for listening. | |
149 | * The constructor takes a callback to call when an FD has been | |
150 | * accept()ed some time later. | |
151 | */ | |
152 | void | |
cbff89ba | 153 | Comm::TcpAcceptor::setListen() |
0ba55a12 | 154 | { |
5dc67d58 | 155 | errcode = errno = 0; |
a9870624 | 156 | if (listen(conn->fd, Squid_MaxFD >> 2) < 0) { |
0ba55a12 | 157 | errcode = errno; |
ccfbe8f4 | 158 | debugs(50, DBG_CRITICAL, "ERROR: listen(..., " << (Squid_MaxFD >> 2) << ") system call failed: " << xstrerr(errcode)); |
0ba55a12 AJ |
159 | return; |
160 | } | |
161 | ||
162 | if (Config.accept_filter && strcmp(Config.accept_filter, "none") != 0) { | |
163 | #ifdef SO_ACCEPTFILTER | |
164 | struct accept_filter_arg afa; | |
165 | bzero(&afa, sizeof(afa)); | |
5b67dfa4 | 166 | debugs(5, DBG_IMPORTANT, "Installing accept filter '" << Config.accept_filter << "' on " << conn); |
0ba55a12 | 167 | xstrncpy(afa.af_name, Config.accept_filter, sizeof(afa.af_name)); |
b69e9ffa AJ |
168 | if (setsockopt(conn->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) { |
169 | int xerrno = errno; | |
170 | debugs(5, DBG_CRITICAL, "WARNING: SO_ACCEPTFILTER '" << Config.accept_filter << "': '" << xstrerr(xerrno)); | |
171 | } | |
0ba55a12 AJ |
172 | #elif defined(TCP_DEFER_ACCEPT) |
173 | int seconds = 30; | |
174 | if (strncmp(Config.accept_filter, "data=", 5) == 0) | |
175 | seconds = atoi(Config.accept_filter + 5); | |
b69e9ffa AJ |
176 | if (setsockopt(conn->fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &seconds, sizeof(seconds)) < 0) { |
177 | int xerrno = errno; | |
178 | debugs(5, DBG_CRITICAL, "WARNING: TCP_DEFER_ACCEPT '" << Config.accept_filter << "': '" << xstrerr(xerrno)); | |
179 | } | |
0ba55a12 | 180 | #else |
5b67dfa4 | 181 | debugs(5, DBG_CRITICAL, "WARNING: accept_filter not supported on your OS"); |
0ba55a12 AJ |
182 | #endif |
183 | } | |
6f09127c | 184 | |
c6f168c1 CT |
185 | #if 0 |
186 | // Untested code. | |
187 | // Set TOS if needed. | |
188 | // To correctly implement TOS values on listening sockets, probably requires | |
189 | // more work to inherit TOS values to created connection objects. | |
4b77ea6b | 190 | if (conn->tos) |
6f9bd9b2 | 191 | Ip::Qos::setSockTos(conn, conn->tos) |
c6f168c1 | 192 | #if SO_MARK |
6f9bd9b2 | 193 | if (conn->nfmark) |
4b77ea6b | 194 | Ip::Qos::setSockNfmark(conn, conn->nfmark); |
c6f168c1 CT |
195 | #endif |
196 | #endif | |
197 | ||
6f09127c AR |
198 | typedef CommCbMemFunT<Comm::TcpAcceptor, CommCloseCbParams> Dialer; |
199 | closer_ = JobCallback(5, 4, Dialer, this, Comm::TcpAcceptor::handleClosure); | |
200 | comm_add_close_handler(conn->fd, closer_); | |
201 | } | |
202 | ||
203 | /// called when listening descriptor is closed by an external force | |
204 | /// such as clientHttpConnectionsClose() | |
205 | void | |
ced8def3 | 206 | Comm::TcpAcceptor::handleClosure(const CommCloseCbParams &) |
6f09127c AR |
207 | { |
208 | closer_ = NULL; | |
209 | conn = NULL; | |
210 | Must(done()); | |
04f55905 AJ |
211 | } |
212 | ||
213 | /** | |
214 | * This private callback is called whenever a filedescriptor is ready | |
215 | * to dupe itself and fob off an accept()ed connection | |
216 | * | |
217 | * It will either do that accept operation. Or if there are not enough FD | |
218 | * available to do the clone safely will push the listening FD into a list | |
219 | * of deferred operations. The list gets kicked and the dupe/accept() actually | |
220 | * done later when enough sockets become available. | |
221 | */ | |
222 | void | |
cbff89ba | 223 | Comm::TcpAcceptor::doAccept(int fd, void *data) |
04f55905 | 224 | { |
5b67dfa4 AJ |
225 | try { |
226 | debugs(5, 2, HERE << "New connection on FD " << fd); | |
04f55905 | 227 | |
5b67dfa4 | 228 | Must(isOpen(fd)); |
cbff89ba | 229 | TcpAcceptor *afd = static_cast<TcpAcceptor*>(data); |
04f55905 | 230 | |
5b67dfa4 AJ |
231 | if (!okToAccept()) { |
232 | AcceptLimiter::Instance().defer(afd); | |
233 | } else { | |
234 | afd->acceptNext(); | |
235 | } | |
5b67dfa4 | 236 | |
db98b2bd | 237 | } catch (const std::exception &e) { |
cbff89ba | 238 | fatalf("FATAL: error while accepting new client connection: %s\n", e.what()); |
db98b2bd | 239 | } catch (...) { |
fbdf945d | 240 | fatal("FATAL: error while accepting new client connection: [unknown]\n"); |
04f55905 | 241 | } |
04f55905 AJ |
242 | } |
243 | ||
244 | bool | |
cbff89ba | 245 | Comm::TcpAcceptor::okToAccept() |
04f55905 AJ |
246 | { |
247 | static time_t last_warn = 0; | |
248 | ||
249 | if (fdNFree() >= RESERVED_FD) | |
250 | return true; | |
251 | ||
252 | if (last_warn + 15 < squid_curtime) { | |
253 | debugs(5, DBG_CRITICAL, "WARNING! Your cache is running out of filedescriptors"); | |
254 | last_warn = squid_curtime; | |
255 | } | |
256 | ||
257 | return false; | |
258 | } | |
259 | ||
ccfbe8f4 AR |
260 | void |
261 | Comm::TcpAcceptor::logAcceptError(const ConnectionPointer &tcpClient) const | |
da6dbcd1 EB |
262 | { |
263 | AccessLogEntry::Pointer al = new AccessLogEntry; | |
ccfbe8f4 AR |
264 | CodeContext::Reset(al); |
265 | al->tcpClient = tcpClient; | |
da6dbcd1 | 266 | al->url = "error:accept-client-connection"; |
bec110e4 | 267 | al->setVirginUrlForMissingRequest(al->url); |
da6dbcd1 | 268 | ACLFilledChecklist ch(nullptr, nullptr, nullptr); |
ccfbe8f4 AR |
269 | ch.src_addr = tcpClient->remote; |
270 | ch.my_addr = tcpClient->local; | |
cb365059 | 271 | ch.al = al; |
da6dbcd1 | 272 | accessLogLog(al, &ch); |
ccfbe8f4 AR |
273 | |
274 | CodeContext::Reset(listenPort_); | |
da6dbcd1 EB |
275 | } |
276 | ||
971581ee | 277 | void |
cbff89ba | 278 | Comm::TcpAcceptor::acceptOne() |
04f55905 AJ |
279 | { |
280 | /* | |
281 | * We don't worry about running low on FDs here. Instead, | |
282 | * doAccept() will use AcceptLimiter if we reach the limit | |
283 | * there. | |
284 | */ | |
285 | ||
286 | /* Accept a new connection */ | |
5b67dfa4 | 287 | ConnectionPointer newConnDetails = new Connection(); |
c8407295 | 288 | const Comm::Flag flag = oldAccept(newConnDetails); |
04f55905 | 289 | |
29a0bb6a | 290 | if (flag == Comm::COMM_ERROR) { |
04f55905 | 291 | // A non-recoverable error; notify the caller */ |
cbff89ba | 292 | debugs(5, 5, HERE << "non-recoverable error:" << status() << " handler Subscription: " << theCallSub); |
da6dbcd1 EB |
293 | if (intendedForUserConnections()) |
294 | logAcceptError(newConnDetails); | |
8bbb16e3 | 295 | notify(flag, newConnDetails); |
5b67dfa4 | 296 | mustStop("Listener socket closed"); |
971581ee | 297 | return; |
04f55905 AJ |
298 | } |
299 | ||
29a0bb6a AJ |
300 | if (flag == Comm::NOMESSAGE) { |
301 | /* register interest again */ | |
302 | debugs(5, 5, "try later: " << conn << " handler Subscription: " << theCallSub); | |
303 | } else { | |
ccfbe8f4 AR |
304 | // TODO: When ALE, MasterXaction merge, use them or ClientConn instead. |
305 | CodeContext::Reset(newConnDetails); | |
29a0bb6a AJ |
306 | debugs(5, 5, "Listener: " << conn << |
307 | " accepted new connection " << newConnDetails << | |
308 | " handler Subscription: " << theCallSub); | |
309 | notify(flag, newConnDetails); | |
ccfbe8f4 | 310 | CodeContext::Reset(listenPort_); |
29a0bb6a | 311 | } |
653d9927 | 312 | |
f3b976f7 | 313 | SetSelect(conn->fd, COMM_SELECT_READ, doAccept, this, 0); |
04f55905 AJ |
314 | } |
315 | ||
316 | void | |
cbff89ba | 317 | Comm::TcpAcceptor::acceptNext() |
04f55905 | 318 | { |
a9870624 | 319 | Must(IsConnOpen(conn)); |
5b67dfa4 | 320 | debugs(5, 2, HERE << "connection on " << conn); |
971581ee | 321 | acceptOne(); |
04f55905 AJ |
322 | } |
323 | ||
324 | void | |
c8407295 | 325 | Comm::TcpAcceptor::notify(const Comm::Flag flag, const Comm::ConnectionPointer &newConnDetails) const |
04f55905 | 326 | { |
c8407295 | 327 | // listener socket handlers just abandon the port with Comm::ERR_CLOSING |
04f55905 | 328 | // it should only happen when this object is deleted... |
c8407295 | 329 | if (flag == Comm::ERR_CLOSING) { |
04f55905 AJ |
330 | return; |
331 | } | |
332 | ||
5b67dfa4 AJ |
333 | if (theCallSub != NULL) { |
334 | AsyncCall::Pointer call = theCallSub->callback(); | |
335 | CommAcceptCbParams ¶ms = GetCommParams<CommAcceptCbParams>(call); | |
5ceaee75 | 336 | params.xaction = new MasterXaction(XactionInitiator::initClient); |
fa720bfb | 337 | params.xaction->squidPort = listenPort_; |
a9870624 | 338 | params.fd = conn->fd; |
94bfd31f | 339 | params.conn = params.xaction->tcpClient = newConnDetails; |
0ba55a12 AJ |
340 | params.flag = flag; |
341 | params.xerrno = errcode; | |
342 | ScheduleCallHere(call); | |
0ba55a12 | 343 | } |
04f55905 AJ |
344 | } |
345 | ||
346 | /** | |
97b8ac39 | 347 | * accept() and process |
5b67dfa4 AJ |
348 | * Wait for an incoming connection on our listener socket. |
349 | * | |
61beade2 AJ |
350 | * \retval Comm::OK success. details parameter filled. |
351 | * \retval Comm::NOMESSAGE attempted accept() but nothing useful came in. | |
61beade2 | 352 | * Or this client has too many connections already. |
29a0bb6a | 353 | * \retval Comm::COMM_ERROR an outright failure occurred. |
273f66c4 | 354 | */ |
c8407295 | 355 | Comm::Flag |
8bbb16e3 | 356 | Comm::TcpAcceptor::oldAccept(Comm::ConnectionPointer &details) |
04f55905 AJ |
357 | { |
358 | PROF_start(comm_accept); | |
e4f1fdae | 359 | ++statCounter.syscalls.sock.accepts; |
04f55905 AJ |
360 | int sock; |
361 | struct addrinfo *gai = NULL; | |
851614a8 | 362 | Ip::Address::InitAddr(gai); |
04f55905 | 363 | |
1fc32b95 | 364 | errcode = 0; // reset local errno copy. |
a9870624 | 365 | if ((sock = accept(conn->fd, gai->ai_addr, &gai->ai_addrlen)) < 0) { |
1fc32b95 | 366 | errcode = errno; // store last accept errno locally. |
04f55905 | 367 | |
851614a8 | 368 | Ip::Address::FreeAddr(gai); |
04f55905 AJ |
369 | |
370 | PROF_stop(comm_accept); | |
371 | ||
fb730aad | 372 | if (ignoreErrno(errcode) || errcode == ECONNABORTED) { |
b69e9ffa | 373 | debugs(50, 5, status() << ": " << xstrerr(errcode)); |
c8407295 | 374 | return Comm::NOMESSAGE; |
fb730aad | 375 | } else if (errcode == ENFILE || errcode == EMFILE) { |
b69e9ffa | 376 | debugs(50, 3, status() << ": " << xstrerr(errcode)); |
4ee57cbe | 377 | return Comm::COMM_ERROR; |
04f55905 | 378 | } else { |
ccfbe8f4 | 379 | debugs(50, DBG_IMPORTANT, "ERROR: failed to accept an incoming connection: " << xstrerr(errcode)); |
4ee57cbe | 380 | return Comm::COMM_ERROR; |
04f55905 AJ |
381 | } |
382 | } | |
383 | ||
a9870624 | 384 | Must(sock >= 0); |
5b67dfa4 AJ |
385 | details->fd = sock; |
386 | details->remote = *gai; | |
04f55905 | 387 | |
903198a7 | 388 | // lookup the local-end details of this new connection |
851614a8 | 389 | Ip::Address::InitAddr(gai); |
4dd643d5 | 390 | details->local.setEmpty(); |
e42281f9 | 391 | if (getsockname(sock, gai->ai_addr, &gai->ai_addrlen) != 0) { |
b69e9ffa AJ |
392 | int xerrno = errno; |
393 | debugs(50, DBG_IMPORTANT, "ERROR: getsockname() failed to locate local-IP on " << details << ": " << xstrerr(xerrno)); | |
851614a8 | 394 | Ip::Address::FreeAddr(gai); |
6558fd54 | 395 | PROF_stop(comm_accept); |
4ee57cbe | 396 | return Comm::COMM_ERROR; |
e42281f9 | 397 | } |
5b67dfa4 | 398 | details->local = *gai; |
851614a8 | 399 | Ip::Address::FreeAddr(gai); |
04f55905 | 400 | |
40d34a62 AJ |
401 | // Perform NAT or TPROXY operations to retrieve the real client/dest IP addresses |
402 | if (conn->flags&(COMM_TRANSPARENT|COMM_INTERCEPTION) && !Ip::Interceptor.Lookup(details, conn)) { | |
ae0d2b74 | 403 | debugs(50, DBG_IMPORTANT, "ERROR: NAT/TPROXY lookup failed to locate original IPs on " << details); |
40d34a62 | 404 | // Failed. |
6558fd54 | 405 | PROF_stop(comm_accept); |
4ee57cbe | 406 | return Comm::COMM_ERROR; |
40d34a62 | 407 | } |
04f55905 | 408 | |
83b62d3f AJ |
409 | #if USE_SQUID_EUI |
410 | if (Eui::TheConfig.euiLookup) { | |
68e47c3e AJ |
411 | if (details->remote.isIPv4()) { |
412 | details->remoteEui48.lookup(details->remote); | |
413 | } else if (details->remote.isIPv6()) { | |
414 | details->remoteEui64.lookup(details->remote); | |
83b62d3f AJ |
415 | } |
416 | } | |
417 | #endif | |
418 | ||
29a0bb6a AJ |
419 | details->nfConnmark = Ip::Qos::getNfConnmark(details, Ip::Qos::dirAccepted); |
420 | ||
421 | if (Config.client_ip_max_connections >= 0) { | |
422 | if (clientdbEstablished(details->remote, 0) > Config.client_ip_max_connections) { | |
423 | debugs(50, DBG_IMPORTANT, "WARNING: " << details->remote << " attempting more than " << Config.client_ip_max_connections << " connections."); | |
424 | PROF_stop(comm_accept); | |
425 | return Comm::NOMESSAGE; | |
426 | } | |
427 | } | |
428 | ||
429 | /* fdstat update */ | |
430 | // XXX : these are not all HTTP requests. use a note about type and ip:port details-> | |
431 | // so we end up with a uniform "(HTTP|FTP-data|HTTPS|...) remote-ip:remote-port" | |
432 | fd_open(sock, FD_SOCKET, "HTTP Request"); | |
433 | ||
434 | fde *F = &fd_table[sock]; | |
435 | details->remote.toStr(F->ipaddr,MAX_IPSTRLEN); | |
436 | F->remote_port = details->remote.port(); | |
437 | F->local_addr = details->local; | |
438 | F->sock_family = details->local.isIPv6()?AF_INET6:AF_INET; | |
439 | ||
440 | // set socket flags | |
441 | commSetCloseOnExec(sock); | |
442 | commSetNonBlocking(sock); | |
443 | ||
444 | /* IFF the socket is (tproxy) transparent, pass the flag down to allow spoofing */ | |
445 | F->flags.transparent = fd_table[conn->fd].flags.transparent; // XXX: can we remove this line yet? | |
446 | ||
04f55905 | 447 | PROF_stop(comm_accept); |
c8407295 | 448 | return Comm::OK; |
04f55905 | 449 | } |
f53969cc | 450 |