]> git.ipfire.org Git - thirdparty/squid.git/blame - src/comm.cc
cleanup gratuitous cbdata locks/unlocks
[thirdparty/squid.git] / src / comm.cc
CommitLineData
da2b3a17 1
1afe05c5 2
30a4f2a8 3/*
04905c93 4 * $Id: comm.cc,v 1.270 1998/06/09 23:34:00 wessels Exp $
30a4f2a8 5 *
6 * DEBUG: section 5 Socket Functions
7 * AUTHOR: Harvest Derived
8 *
42c04c16 9 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
30a4f2a8 10 * --------------------------------------------------------
11 *
12 * Squid is the result of efforts by numerous individuals from the
13 * Internet community. Development is led by Duane Wessels of the
14 * National Laboratory for Applied Network Research and funded by
15 * the National Science Foundation.
16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30 *
31 */
d1f14731 32
30a4f2a8 33/*
34 * Copyright (c) 1994, 1995. All rights reserved.
35 *
36 * The Harvest software was developed by the Internet Research Task
37 * Force Research Group on Resource Discovery (IRTF-RD):
38 *
39 * Mic Bowman of Transarc Corporation.
40 * Peter Danzig of the University of Southern California.
41 * Darren R. Hardy of the University of Colorado at Boulder.
42 * Udi Manber of the University of Arizona.
43 * Michael F. Schwartz of the University of Colorado at Boulder.
44 * Duane Wessels of the University of Colorado at Boulder.
45 *
46 * This copyright notice applies to software in the Harvest
47 * ``src/'' directory only. Users should consult the individual
48 * copyright notices in the ``components/'' subdirectories for
49 * copyright information about other software bundled with the
50 * Harvest source code distribution.
51 *
52 * TERMS OF USE
53 *
54 * The Harvest software may be used and re-distributed without
55 * charge, provided that the software origin and research team are
56 * cited in any use of the system. Most commonly this is
57 * accomplished by including a link to the Harvest Home Page
58 * (http://harvest.cs.colorado.edu/) from the query page of any
59 * Broker you deploy, as well as in the query result pages. These
60 * links are generated automatically by the standard Broker
61 * software distribution.
62 *
63 * The Harvest software is provided ``as is'', without express or
64 * implied warranty, and with no support nor obligation to assist
65 * in its use, correction, modification or enhancement. We assume
66 * no liability with respect to the infringement of copyrights,
67 * trade secrets, or any patents, and are not responsible for
68 * consequential damages. Proper use of the Harvest software is
69 * entirely the responsibility of the user.
70 *
71 * DERIVATIVE WORKS
72 *
73 * Users may make derivative works from the Harvest software, subject
74 * to the following constraints:
75 *
76 * - You must include the above copyright notice and these
77 * accompanying paragraphs in all forms of derivative works,
78 * and any documentation and other materials related to such
79 * distribution and use acknowledge that the software was
80 * developed at the above institutions.
81 *
82 * - You must notify IRTF-RD regarding your distribution of
83 * the derivative work.
84 *
85 * - You must clearly notify users that your are distributing
86 * a modified version and not the original Harvest software.
87 *
88 * - Any derivative product is also subject to these copyright
89 * and use restrictions.
90 *
91 * Note that the Harvest software is NOT in the public domain. We
92 * retain copyright, as specified above.
93 *
94 * HISTORY OF FREE SOFTWARE STATUS
95 *
96 * Originally we required sites to license the software in cases
97 * where they were going to build commercial products/services
98 * around Harvest. In June 1995 we changed this policy. We now
99 * allow people to use the core Harvest software (the code found in
100 * the Harvest ``src/'' directory) for free. We made this change
101 * in the interest of encouraging the widest possible deployment of
102 * the technology. The Harvest software is really a reference
103 * implementation of a set of protocols and formats, some of which
104 * we intend to standardize. We encourage commercial
105 * re-implementations of code complying to this set of standards.
106 */
090089c4 107
44a47c6e 108#include "squid.h"
0a0bf5db 109#include <errno.h>
090089c4 110
30a4f2a8 111#ifdef HAVE_NETINET_TCP_H
112#include <netinet/tcp.h>
113#endif
090089c4 114
52040193 115#if USE_ASYNC_IO
116#define MAX_POLL_TIME 50
117#else
118#define MAX_POLL_TIME 1000
119#endif
120
f88211e8 121typedef struct {
122 char *host;
123 u_short port;
124 struct sockaddr_in S;
125 CNCB *callback;
126 void *data;
f88211e8 127 struct in_addr in_addr;
128 int locks;
03a1ee42 129 int fd;
22c653cd 130 int tries;
131 int addrcount;
132 int connstart;
f88211e8 133} ConnectStateData;
134
090089c4 135/* STATIC */
ba4f8e5a 136static int incame = 0;
f5b8bbc4 137static int commBind(int s, struct in_addr, u_short port);
f88211e8 138#if !HAVE_POLL
f5b8bbc4 139static int examine_select(fd_set *, fd_set *);
dcfe6390 140#endif
f5b8bbc4 141static void checkTimeouts(void);
142static void commSetReuseAddr(int);
143static void commSetNoLinger(int);
ba4f8e5a 144static void comm_incoming(void);
f5b8bbc4 145static void CommWriteStateCallbackAndFree(int fd, int code);
30a4f2a8 146#ifdef TCP_NODELAY
f5b8bbc4 147static void commSetTcpNoDelay(int);
30a4f2a8 148#endif
f5b8bbc4 149static void commSetTcpRcvbuf(int, int);
f88211e8 150static PF commConnectFree;
03a1ee42 151static PF commConnectHandle;
152static PF commHandleWrite;
f5b8bbc4 153static int fdIsHttpOrIcp(int fd);
edeb28fd 154static IPH commConnectDnsHandle;
f5b8bbc4 155static void commConnectCallback(ConnectStateData * cs, int status);
da2b3a17 156static int commDeferRead(int fd);
22c653cd 157static int commResetFD(ConnectStateData * cs);
158static int commRetryConnect(ConnectStateData * cs);
309ad3b6 159static OBJH commIncomingStats;
30a4f2a8 160
30a4f2a8 161static struct timeval zero_tv;
090089c4 162
309ad3b6 163/*
164 * Automatic tuning for incoming requests:
165 *
166 * INCOMING sockets are the ICP and HTTP ports. We need to check these
167 * fairly regularly, but how often? When the load increases, we
168 * want to check the incoming sockets more often. If we have a lot
169 * of incoming ICP, then we need to check these sockets more than
170 * if we just have HTTP.
171 *
172 * The variable 'incoming_interval' determines how many normal I/O
173 * events to process before checking incoming sockets again.
174 * Note we store the incoming_interval multipled by a factor
175 * of 16 (e.g. <<4) to have some pseudo-floating point precision.
176 *
177 * The variable 'io_events' counts how many normal I/O events have
178 * been processed. When io_events > incoming_interval, its time
179 * to check incoming sockets.
180 *
181 * Every time we check incoming sockets, we count how many new messages
182 * or connections were processed. This is used to adjust the
183 * incoming_interval for the next iteration. The new incoming_interval
184 * is calculated as the average of the current incoming_interval and
185 * 32 divided by the number of incoming events just processed. e.g.
186 *
187 * 1 1 32
188 * incoming_interval = - incoming_interval + - -----------------
189 * 2 2 incoming_events
190 *
191 * You can see the current value of incoming_interval, as well as
192 * a histogram of 'incoming_events' by asking the cache manager
193 * for 'comm_incoming', e.g.:
194 *
195 * % ./client mgr:comm_incoming
196 *
197 * Bugs:
198 *
199 * - We have 32 as a magic upper limit on incoming_interval.
200 * - INCOMING_TOTAL_MAX = INCOMING_ICP_MAX + INCOMING_HTTP_MAX,
201 * but this assumes only one ICP socket and one HTTP socket.
202 * If there are multiple incoming HTTP sockets, the we could
203 * conceivably process more than INCOMING_TOTAL_MAX events
204 * in comm_incoming().
205 *
206 * The 'invert32[]' array is a pre-calculated array of division for 32/i
207 *
208 */
209static int io_events = 0;
210static int incoming_interval = 16 << 4;
211static int invert32[INCOMING_TOTAL_MAX];
212#define commCheckIncoming (++io_events > (incoming_interval>>4))
213
b8d8561b 214static void
f17936ab 215CommWriteStateCallbackAndFree(int fd, int code)
9864ee44 216{
f17936ab 217 CommWriteStateData *CommWriteState = fd_table[fd].rwstate;
218 CWCB *callback = NULL;
1a8f5ed6 219 void *data;
a56a3abe 220 fd_table[fd].rwstate = NULL;
f17936ab 221 if (CommWriteState == NULL)
9864ee44 222 return;
c0dec081 223 if (CommWriteState->free_func) {
224 CommWriteState->free_func(CommWriteState->buf);
f17936ab 225 CommWriteState->buf = NULL;
9864ee44 226 }
f17936ab 227 callback = CommWriteState->handler;
1a8f5ed6 228 data = CommWriteState->handler_data;
f17936ab 229 CommWriteState->handler = NULL;
1a8f5ed6 230 if (callback && cbdataValid(data))
231 callback(fd, CommWriteState->buf, CommWriteState->offset, code, data);
232 cbdataUnlock(data);
f17936ab 233 safe_free(CommWriteState);
9864ee44 234}
235
090089c4 236/* Return the local port associated with fd. */
b8d8561b 237u_short
238comm_local_port(int fd)
090089c4 239{
240 struct sockaddr_in addr;
241 int addr_len = 0;
76f87348 242 fde *F = &fd_table[fd];
090089c4 243
090089c4 244 /* If the fd is closed already, just return */
76f87348 245 if (!F->open) {
a3d5953d 246 debug(5, 0) ("comm_local_port: FD %d has been closed.\n", fd);
30a4f2a8 247 return 0;
090089c4 248 }
76f87348 249 if (F->local_port)
250 return F->local_port;
090089c4 251 addr_len = sizeof(addr);
252 if (getsockname(fd, (struct sockaddr *) &addr, &addr_len)) {
a3d5953d 253 debug(50, 1) ("comm_local_port: Failed to retrieve TCP/UDP port number for socket: FD %d: %s\n", fd, xstrerror());
30a4f2a8 254 return 0;
090089c4 255 }
76f87348 256 F->local_port = ntohs(addr.sin_port);
5f6ac48b 257 debug(5, 6) ("comm_local_port: FD %d: port %d\n", fd, (int) F->local_port);
76f87348 258 return F->local_port;
090089c4 259}
260
b8d8561b 261static int
262commBind(int s, struct in_addr in_addr, u_short port)
090089c4 263{
264 struct sockaddr_in S;
090089c4 265
090089c4 266 memset(&S, '\0', sizeof(S));
267 S.sin_family = AF_INET;
268 S.sin_port = htons(port);
30a4f2a8 269 S.sin_addr = in_addr;
090089c4 270 if (bind(s, (struct sockaddr *) &S, sizeof(S)) == 0)
271 return COMM_OK;
a3d5953d 272 debug(50, 0) ("commBind: Cannot bind socket FD %d to %s:%d: %s\n",
090089c4 273 s,
30a4f2a8 274 S.sin_addr.s_addr == INADDR_ANY ? "*" : inet_ntoa(S.sin_addr),
44a62238 275 (int) port,
276 xstrerror());
090089c4 277 return COMM_ERROR;
278}
279
280/* Create a socket. Default is blocking, stream (TCP) socket. IO_TYPE
281 * is OR of flags specified in comm.h. */
b8d8561b 282int
16b204c4 283comm_open(int sock_type,
cc6a9d2e 284 int proto,
285 struct in_addr addr,
286 u_short port,
287 int flags,
0ee4272b 288 const char *note)
090089c4 289{
290 int new_socket;
76f87348 291 fde *F = NULL;
b6f794d6 292 int tcp_rcv_bufsz = Config.tcpRcvBufsz;
090089c4 293
294 /* Create socket for accepting new connections. */
16b204c4 295 if ((new_socket = socket(AF_INET, sock_type, proto)) < 0) {
090089c4 296 /* Increase the number of reserved fd's if calls to socket()
297 * are failing because the open file table is full. This
298 * limits the number of simultaneous clients */
299 switch (errno) {
300 case ENFILE:
301 case EMFILE:
a3d5953d 302 debug(50, 1) ("comm_open: socket failure: %s\n", xstrerror());
090089c4 303 break;
304 default:
a3d5953d 305 debug(50, 0) ("comm_open: socket failure: %s\n", xstrerror());
090089c4 306 }
4b23e114 307 fdAdjustReserved();
603a02fd 308 return -1;
090089c4 309 }
310 /* update fdstat */
365e5b34 311 debug(5, 5) ("comm_open: FD %d is a new socket\n", new_socket);
5c5783a2 312 fd_open(new_socket, FD_SOCKET, note);
76f87348 313 F = &fd_table[new_socket];
79a15e0a 314 if (!(flags & COMM_NOCLOEXEC))
3ca60c86 315 commSetCloseOnExec(new_socket);
cdc33f35 316 if ((flags & COMM_REUSEADDR))
317 commSetReuseAddr(new_socket);
7690e8eb 318 if (port > (u_short) 0) {
30a4f2a8 319 commSetNoLinger(new_socket);
3b4be6a6 320 if (opt_reuseaddr)
090089c4 321 commSetReuseAddr(new_socket);
090089c4 322 }
a3724d50 323 if (addr.s_addr != no_addr.s_addr) {
324 if (commBind(new_socket, addr, port) != COMM_OK) {
325 comm_close(new_socket);
603a02fd 326 return -1;
a3724d50 327 }
23ff6968 328 }
76f87348 329 F->local_port = port;
090089c4 330
79a15e0a 331 if (flags & COMM_NONBLOCKING)
30a4f2a8 332 if (commSetNonBlocking(new_socket) == COMM_ERROR)
603a02fd 333 return -1;
30a4f2a8 334#ifdef TCP_NODELAY
335 if (sock_type == SOCK_STREAM)
336 commSetTcpNoDelay(new_socket);
337#endif
f868539a 338 if (tcp_rcv_bufsz > 0 && sock_type == SOCK_STREAM)
339 commSetTcpRcvbuf(new_socket, tcp_rcv_bufsz);
090089c4 340 return new_socket;
341}
342
b4ea1f2e 343/*
344 * NOTE: set the listen queue to Squid_MaxFD/4 and rely on the kernel to
345 * impose an upper limit. Solaris' listen(3n) page says it has
346 * no limit on this parameter, but sys/socket.h sets SOMAXCONN
347 * to 5. HP-UX currently has a limit of 20. SunOS is 5 and
348 * OSF 3.0 is 8.
349 */
b8d8561b 350int
351comm_listen(int sock)
090089c4 352{
353 int x;
e83892e9 354 if ((x = listen(sock, Squid_MaxFD >> 2)) < 0) {
a3d5953d 355 debug(50, 0) ("comm_listen: listen(%d, %d): %s\n",
e83892e9 356 Squid_MaxFD >> 2,
090089c4 357 sock, xstrerror());
358 return x;
359 }
360 return sock;
361}
362
e5f6c5c2 363void
4f92c80c 364commConnectStart(int fd, const char *host, u_short port, CNCB * callback, void *data)
e924600d 365{
366 ConnectStateData *cs = xcalloc(1, sizeof(ConnectStateData));
04905c93 367 debug(5,3)("commConnectStart: FD %d, %s:%d\n", fd, host, (int) port);
3f6c0fb2 368 cbdataAdd(cs, MEM_NONE);
03a1ee42 369 cs->fd = fd;
e924600d 370 cs->host = xstrdup(host);
371 cs->port = port;
372 cs->callback = callback;
373 cs->data = data;
b716a8ad 374 cbdataLock(cs->data);
e924600d 375 comm_add_close_handler(fd, commConnectFree, cs);
f88211e8 376 cs->locks++;
8407afee 377 ipcache_nbgethostbyname(host, commConnectDnsHandle, cs);
edeb28fd 378}
379
380static void
03a1ee42 381commConnectDnsHandle(const ipcache_addrs * ia, void *data)
edeb28fd 382{
383 ConnectStateData *cs = data;
f88211e8 384 assert(cs->locks == 1);
385 cs->locks--;
edeb28fd 386 if (ia == NULL) {
a3d5953d 387 debug(5, 3) ("commConnectDnsHandle: Unknown host: %s\n", cs->host);
6cf028ab 388 if (!dns_error_message) {
389 dns_error_message = "Unknown DNS error";
0e473d70 390 debug(5, 1) ("commConnectDnsHandle: Bad dns_error_message\n");
6cf028ab 391 }
a64c2869 392 assert(dns_error_message != NULL);
03a1ee42 393 commConnectCallback(cs, COMM_ERR_DNS);
edeb28fd 394 return;
395 }
f076b37b 396 assert(ia->cur < ia->count);
edeb28fd 397 cs->in_addr = ia->in_addrs[ia->cur];
52926044 398 ipcacheCycleAddr(cs->host, NULL);
22c653cd 399 cs->addrcount = ia->count;
400 cs->connstart = squid_curtime;
03a1ee42 401 commConnectHandle(cs->fd, cs);
e924600d 402}
403
f88211e8 404static void
03a1ee42 405commConnectCallback(ConnectStateData * cs, int status)
f88211e8 406{
a3d5953d 407 CNCB *callback = cs->callback;
408 void *data = cs->data;
03a1ee42 409 int fd = cs->fd;
a3d5953d 410 comm_remove_close_handler(fd, commConnectFree, cs);
9daca08e 411 cs->callback = NULL;
412 cs->data = NULL;
e1b16349 413 commSetTimeout(fd, -1, NULL, NULL);
a3d5953d 414 commConnectFree(fd, cs);
8407afee 415 if (cbdataValid(data))
365e5b34 416 callback(fd, status, data);
1790d392 417 cbdataUnlock(data);
f88211e8 418}
419
e924600d 420static void
9daca08e 421commConnectFree(int fd, void *data)
e924600d 422{
423 ConnectStateData *cs = data;
9daca08e 424 debug(5, 3) ("commConnectFree: FD %d\n", fd);
8407afee 425 if (cs->locks)
365e5b34 426 ipcacheUnregister(cs->host, cs);
9daca08e 427 if (cs->data)
428 cbdataUnlock(cs->data);
8407afee 429 safe_free(cs->host);
430 cbdataFree(cs);
e924600d 431}
432
22c653cd 433/* Reset FD so that we can connect() again */
edeb28fd 434static int
22c653cd 435commResetFD(ConnectStateData * cs)
edeb28fd 436{
437 int fd2;
7dd44885 438 if (!cbdataValid(cs->data))
439 return 0;
edeb28fd 440 fd2 = socket(AF_INET, SOCK_STREAM, 0);
441 if (fd2 < 0) {
22c653cd 442 debug(5, 0) ("commResetFD: socket: %s\n", xstrerror());
4b23e114 443 fdAdjustReserved();
edeb28fd 444 return 0;
445 }
22c653cd 446 if (dup2(fd2, cs->fd) < 0) {
447 debug(5, 0) ("commResetFD: dup2: %s\n", xstrerror());
4b23e114 448 fdAdjustReserved();
edeb28fd 449 return 0;
450 }
edeb28fd 451 close(fd2);
22c653cd 452 commSetNonBlocking(cs->fd);
edeb28fd 453 return 1;
454}
455
22c653cd 456static int
457commRetryConnect(ConnectStateData * cs)
458{
459 assert(cs->addrcount > 0);
460 if (cs->addrcount == 1) {
461 if (cs->tries >= Config.retry.maxtries)
462 return 0;
463 if (squid_curtime - cs->connstart > Config.Timeout.connect)
464 return 0;
22c653cd 465 } else {
466 if (cs->tries > cs->addrcount)
467 return 0;
468 }
469 return commResetFD(cs);
470}
471
e924600d 472/* Connect SOCK to specified DEST_PORT at DEST_HOST. */
473static void
474commConnectHandle(int fd, void *data)
090089c4 475{
f88211e8 476 ConnectStateData *cs = data;
477 if (cs->S.sin_addr.s_addr == 0) {
478 cs->S.sin_family = AF_INET;
479 cs->S.sin_addr = cs->in_addr;
480 cs->S.sin_port = htons(cs->port);
17a0a4ee 481 if (Config.onoff.log_fqdn)
f88211e8 482 fqdncache_gethostbyaddr(cs->S.sin_addr, FQDN_LOOKUP_IF_MISS);
e5f6c5c2 483 }
f88211e8 484 switch (comm_connect_addr(fd, &cs->S)) {
e5f6c5c2 485 case COMM_INPROGRESS:
11994bb9 486 debug(5, 5) ("commConnectHandle: FD %d: COMM_INPROGRESS\n", fd);
f88211e8 487 commSetSelect(fd, COMM_SELECT_WRITE, commConnectHandle, cs, 0);
e5f6c5c2 488 break;
489 case COMM_OK:
22c653cd 490 ipcacheMarkGoodAddr(cs->host, cs->S.sin_addr);
03a1ee42 491 commConnectCallback(cs, COMM_OK);
e5f6c5c2 492 break;
493 default:
22c653cd 494 cs->tries++;
495 ipcacheMarkBadAddr(cs->host, cs->S.sin_addr);
194dd3b8 496 if (Config.onoff.test_reachability)
497 netdbDeleteAddrNetwork(cs->S.sin_addr);
22c653cd 498 if (commRetryConnect(cs)) {
f88211e8 499 cs->locks++;
8407afee 500 ipcache_nbgethostbyname(cs->host, commConnectDnsHandle, cs);
edeb28fd 501 } else {
03a1ee42 502 commConnectCallback(cs, COMM_ERR_CONNECT);
edeb28fd 503 }
e5f6c5c2 504 break;
090089c4 505 }
090089c4 506}
22c653cd 507
b8d8561b 508int
4f92c80c 509commSetTimeout(int fd, int timeout, PF * handler, void *data)
090089c4 510{
76f87348 511 fde *F;
a3d5953d 512 debug(5, 3) ("commSetTimeout: FD %d timeout %d\n", fd, timeout);
03eb2f01 513 assert(fd >= 0);
514 assert(fd < Squid_MaxFD);
76f87348 515 F = &fd_table[fd];
0ca54a51 516 assert(F->open);
5c5783a2 517 if (timeout < 0) {
76f87348 518 F->timeout_handler = NULL;
519 F->timeout_data = NULL;
520 return F->timeout = 0;
5c5783a2 521 }
2681d383 522 if (shutting_down) {
4f92c80c 523 /* don't increase the timeout if something pending */
76f87348 524 if (F->timeout > 0 && (int) (F->timeout - squid_curtime) < timeout)
525 return F->timeout;
5c5783a2 526 }
76f87348 527 assert(handler || F->timeout_handler);
5c5783a2 528 if (handler || data) {
76f87348 529 F->timeout_handler = handler;
530 F->timeout_data = data;
30a4f2a8 531 }
76f87348 532 return F->timeout = squid_curtime + (time_t) timeout;
090089c4 533}
534
b8d8561b 535int
0ee4272b 536comm_connect_addr(int sock, const struct sockaddr_in *address)
090089c4 537{
538 int status = COMM_OK;
76f87348 539 fde *F = &fd_table[sock];
090089c4 540 int len;
541 int x;
489b22c1 542 assert(ntohs(address->sin_port) != 0);
090089c4 543 /* Establish connection. */
086bce16 544 if (connect(sock, (struct sockaddr *) address, sizeof(struct sockaddr_in)) < 0) {
365e5b34 545 debug(5, 9) ("connect FD %d: %s\n", sock, xstrerror());
f81b2bec 546#ifdef _SQUID_HPUX_
603500e7 547 if (EALREADY == errno) {
f81b2bec 548 /*
549 * On my HP-UX box (HP-UX tirana B.10.10 A 9000/851),
550 * we get into fast loops on EALREADY. select(2) continually
551 * says the FD is ready for writing, but connect always
552 * returns EALREADY. I applied a patch (PHNE_12906) but
164f7660 553 * it didn't help. -DW Dec 1, 1997
f81b2bec 554 */
555 debug(50, 1) ("connect: %s:%d: %s.\n",
556 fqdnFromAddr(address->sin_addr),
557 ntohs(address->sin_port),
558 xstrerror());
559 return COMM_ERROR;
603500e7 560 } else
30a4f2a8 561#endif
603500e7 562 if (ignoreErrno(errno)) {
e5f6c5c2 563 status = COMM_INPROGRESS;
603500e7 564 } else if (EISCONN == errno) {
090089c4 565 status = COMM_OK;
603500e7 566 } else {
567 if (EINVAL == errno) {
568 len = sizeof(x);
569 if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *) &x, &len) >= 0)
570 errno = x;
571 }
a3d5953d 572 debug(50, 2) ("connect: %s:%d: %s.\n",
28ab0c0a 573 fqdnFromAddr(address->sin_addr),
090089c4 574 ntohs(address->sin_port),
575 xstrerror());
576 return COMM_ERROR;
577 }
e5f6c5c2 578 }
76f87348 579 xstrncpy(F->ipaddr, inet_ntoa(address->sin_addr), 16);
580 F->remote_port = ntohs(address->sin_port);
090089c4 581 if (status == COMM_OK) {
a3d5953d 582 debug(5, 10) ("comm_connect_addr: FD %d connected to %s:%d\n",
76f87348 583 sock, F->ipaddr, F->remote_port);
f21cd581 584 } else if (status == COMM_INPROGRESS) {
a3d5953d 585 debug(5, 10) ("comm_connect_addr: FD %d connection pending\n", sock);
090089c4 586 }
587 /* Add new socket to list of open sockets. */
090089c4 588 return status;
589}
590
591/* Wait for an incoming connection on FD. FD should be a socket returned
592 * from comm_listen. */
b8d8561b 593int
594comm_accept(int fd, struct sockaddr_in *peer, struct sockaddr_in *me)
090089c4 595{
596 int sock;
1f9afe33 597 struct sockaddr_in P;
598 struct sockaddr_in M;
090089c4 599 int Slen;
76f87348 600 fde *F = NULL;
1f9afe33 601 Slen = sizeof(P);
603500e7 602 if ((sock = accept(fd, (struct sockaddr *) &P, &Slen)) < 0) {
603 if (ignoreErrno(errno)) {
604 debug(50, 5) ("comm_accept: FD %d: %s\n", fd, xstrerror());
0a0bf5db 605 return COMM_NOMESSAGE;
603500e7 606 } else if (ENFILE == errno || EMFILE == errno) {
607 debug(50, 3) ("comm_accept: FD %d: %s\n", fd, xstrerror());
090089c4 608 return COMM_ERROR;
603500e7 609 } else {
610 debug(50, 1) ("comm_accept: FD %d: %s\n", fd, xstrerror());
090089c4 611 return COMM_ERROR;
612 }
613 }
090089c4 614 if (peer)
1f9afe33 615 *peer = P;
4053a845 616 Slen = sizeof(M);
617 memset(&M, '\0', Slen);
618 getsockname(sock, (struct sockaddr *) &M, &Slen);
619 if (me)
1f9afe33 620 *me = M;
3ca60c86 621 commSetCloseOnExec(sock);
090089c4 622 /* fdstat update */
5c5783a2 623 fd_open(sock, FD_SOCKET, "HTTP Request");
76f87348 624 F = &fd_table[sock];
c0dec081 625 xstrncpy(F->ipaddr, inet_ntoa(P.sin_addr), 16);
76f87348 626 F->remote_port = htons(P.sin_port);
627 F->local_port = htons(M.sin_port);
090089c4 628 commSetNonBlocking(sock);
090089c4 629 return sock;
630}
631
cb201b7e 632void
633commCallCloseHandlers(int fd)
634{
76f87348 635 fde *F = &fd_table[fd];
f1dc9b30 636 close_handler *ch;
a3d5953d 637 debug(5, 5) ("commCallCloseHandlers: FD %d\n", fd);
76f87348 638 while ((ch = F->close_handler) != NULL) {
639 F->close_handler = ch->next;
9daca08e 640 debug(5, 5) ("commCallCloseHandlers: ch->handler=%p\n", ch->handler);
603a02fd 641 if (cbdataValid(ch->data))
642 ch->handler(fd, ch->data);
643 cbdataUnlock(ch->data);
cb201b7e 644 safe_free(ch);
645 }
646}
647
5492ad1d 648#if LINGERING_CLOSE
649static void
650commLingerClose(int fd, void *unused)
651{
652 LOCAL_ARRAY(char, buf, 1024);
653 int n;
654 n = read(fd, buf, 1024);
655 if (n < 0)
656 debug(5, 3) ("commLingerClose: FD %d read: %s\n", fd, xstrerror());
657 comm_close(fd);
658}
659
660static void
661commLingerTimeout(int fd, void *unused)
662{
663 debug(5, 3) ("commLingerTimeout: FD %d\n", fd);
664 comm_close(fd);
665}
666
667/*
668 * Inspired by apache
669 */
670void
671comm_lingering_close(int fd)
672{
673 if (shutdown(fd, 1) < 0) {
674 comm_close(fd);
675 return;
676 }
677 fd_note(fd, "lingering close");
678 commSetTimeout(fd, 10, commLingerTimeout, NULL);
679 commSetSelect(fd, COMM_SELECT_READ, commLingerClose, NULL, 0);
680}
681#endif
682
b8d8561b 683void
684comm_close(int fd)
090089c4 685{
76f87348 686 fde *F = NULL;
6444c441 687#if USE_ASYNC_IO
c41fa515 688 int doaioclose = 1;
6444c441 689#endif
a3d5953d 690 debug(5, 5) ("comm_close: FD %d\n", fd);
03eb2f01 691 assert(fd >= 0);
692 assert(fd < Squid_MaxFD);
76f87348 693 F = &fd_table[fd];
58a6c186 694 if (F->flags.closing)
e102ebda 695 return;
2681d383 696 if (shutting_down && (!F->open || F->type == FD_FILE))
6cf028ab 697 return;
b716a8ad 698 assert(F->open);
76f87348 699 assert(F->type != FD_FILE);
c41fa515 700#ifdef USE_ASYNC_IO
58a6c186 701 if (F->flags.nolinger && F->flags.nonblocking)
702 doaioclose = 0;
c41fa515 703#endif
58a6c186 704 F->flags.closing = 1;
96f1be5d 705 CommWriteStateCallbackAndFree(fd, COMM_ERR_CLOSING);
cb201b7e 706 commCallCloseHandlers(fd);
b716a8ad 707 if (F->uses) /* assume persistent connect count */
708 pconnHistCount(1, F->uses);
5c5783a2 709 fd_close(fd); /* update fdstat */
5874bf28 710#if defined(_SQUID_LINUX_)
711 /*
712 * michael@metal.iinet.net.au sez close() on
713 * network sockets never blocks.
714 */
715 close(fd);
56ed7af5 716#elif USE_ASYNC_IO
c41fa515 717 if (doaioclose)
6444c441 718 aioClose(fd);
6444c441 719 else
c41fa515 720 close(fd);
0a0bf5db 721#else
9864ee44 722 close(fd);
0a0bf5db 723#endif
090089c4 724}
725
090089c4 726/* Send a udp datagram to specified TO_ADDR. */
b8d8561b 727int
5df61230 728comm_udp_sendto(int fd,
729 const struct sockaddr_in *to_addr,
730 int addr_len,
17b6e784 731 const void *buf,
5df61230 732 int len)
090089c4 733{
5df61230 734 int x;
735 x = sendto(fd, buf, len, 0, (struct sockaddr *) to_addr, addr_len);
736 if (x < 0) {
17d51783 737#ifdef _SQUID_LINUX_
738 if (ECONNREFUSED != errno)
739#endif
740 debug(50, 1) ("comm_udp_sendto: FD %d, %s, port %d: %s\n",
741 fd,
742 inet_ntoa(to_addr->sin_addr),
743 (int) htons(to_addr->sin_port),
744 xstrerror());
090089c4 745 return COMM_ERROR;
746 }
5df61230 747 return x;
090089c4 748}
749
b8d8561b 750void
70a9dab4 751commSetDefer(int fd, DEFER * func, void *data)
4883993a 752{
da2b3a17 753 fde *F = &fd_table[fd];
754 F->defer_check = func;
70a9dab4 755 F->defer_data = data;
4883993a 756}
757
da2b3a17 758static int
759commDeferRead(int fd)
760{
761 fde *F = &fd_table[fd];
762 if (F->defer_check == NULL)
763 return 0;
70a9dab4 764 return F->defer_check(fd, F->defer_data);
da2b3a17 765}
dcfe6390 766
ba4f8e5a 767static void
768comm_incoming(void)
769{
770 int j;
771 incame = 0;
309ad3b6 772 io_events = 0;
47743c14 773 if (theInIcpConnection > 0) {
ba4f8e5a 774 icpHandleUdp(theInIcpConnection, &incame);
309ad3b6 775 if (theInIcpConnection != theOutIcpConnection)
82c0f185 776 icpHandleUdp(theOutIcpConnection, &incame);
777 }
ba4f8e5a 778 for (j = 0; j < NHttpSockets; j++) {
779 if (HttpSockets[j] < 0)
780 continue;
781 httpAccept(HttpSockets[j], &incame);
782 }
783 statHistCount(&Counter.comm_incoming, incame);
309ad3b6 784 if (incame < INCOMING_TOTAL_MAX)
785 incoming_interval = (incoming_interval >> 1) + (invert32[incame] << 3);
ba4f8e5a 786}
787
812ed90c 788static int
789fdIsHttpOrIcp(int fd)
790{
791 int j;
792 if (fd == theInIcpConnection)
793 return 1;
794 if (fd == theOutIcpConnection)
795 return 1;
796 for (j = 0; j < NHttpSockets; j++) {
797 if (fd == HttpSockets[j])
798 return 1;
799 }
800 return 0;
801}
802
f88211e8 803#if HAVE_POLL
dcfe6390 804/* poll all sockets; call handlers for those that are ready. */
805int
52040193 806comm_poll(int msec)
dcfe6390 807{
0a0bf5db 808 struct pollfd pfds[SQUID_MAXFD];
582b6456 809 PF *hdl = NULL;
dcfe6390 810 int fd;
811 int i;
812 int maxfd;
996a0a51 813 unsigned long nfds;
dcfe6390 814 int num;
dcfe6390 815 static time_t last_timeout = 0;
97c03d3c 816 static int lastinc = 0;
52040193 817 double timeout = current_dtime + (msec / 1000.0);
dcfe6390 818 do {
b984c445 819#if !ALARM_UPDATES_TIME
820 getCurrentTime();
821#endif
2681d383 822 if (shutting_down) {
dcfe6390 823 serverConnectionsClose();
dcfe6390 824 dnsShutdownServers();
825 redirectShutdownServers();
2681d383 826 /* shutting_down will be set to
429fdbec 827 * +1 for SIGTERM
828 * -1 for SIGINT */
2681d383 829 if (shutting_down > 0)
5c5783a2 830 setSocketShutdownLifetimes(Config.shutdownLifetime);
dcfe6390 831 else
9e4ad609 832 setSocketShutdownLifetimes(1);
dcfe6390 833 }
6cf028ab 834#if USE_ASYNC_IO
835 aioCheckCallbacks();
836#endif
ba4f8e5a 837 comm_incoming();
429fdbec 838 nfds = 0;
839 maxfd = Biggest_FD + 1;
429fdbec 840 for (i = 0; i < maxfd; i++) {
841 int events;
842 events = 0;
dcfe6390 843 /* Check each open socket for a handler. */
da2b3a17 844 if (fd_table[i].read_handler && !commDeferRead(i))
429fdbec 845 events |= POLLRDNORM;
846 if (fd_table[i].write_handler)
847 events |= POLLWRNORM;
848 if (events) {
429fdbec 849 pfds[nfds].fd = i;
850 pfds[nfds].events = events;
851 pfds[nfds].revents = 0;
852 nfds++;
055f4d4d 853 }
0b2421ea 854 }
2681d383 855 if (shutting_down)
a3d5953d 856 debug(5, 2) ("comm_poll: Still waiting on %d FDs\n", nfds);
dcfe6390 857 if (nfds == 0)
858 return COMM_SHUTDOWN;
52040193 859 if (msec > MAX_POLL_TIME)
860 msec = MAX_POLL_TIME;
dcfe6390 861 for (;;) {
52040193 862 num = poll(pfds, nfds, msec);
f2908497 863 Counter.select_loops++;
dcfe6390 864 if (num >= 0)
865 break;
ee264d61 866 if (ignoreErrno(errno))
0a0bf5db 867 continue;
a3d5953d 868 debug(5, 0) ("comm_poll: poll failure: %s\n", xstrerror());
03eb2f01 869 assert(errno != EINVAL);
dcfe6390 870 return COMM_ERROR;
871 /* NOTREACHED */
872 }
a3d5953d 873 debug(5, num ? 5 : 8) ("comm_poll: %d sockets ready\n", num);
5c5783a2 874 /* Check timeout handlers ONCE each second. */
dcfe6390 875 if (squid_curtime > last_timeout) {
876 last_timeout = squid_curtime;
877 checkTimeouts();
dcfe6390 878 }
879 if (num == 0)
880 continue;
881 /* scan each socket but the accept socket. Poll this
2c5294ce 882 * more frequently to minimize losses due to the 5 connect
dcfe6390 883 * limit in SunOS */
429fdbec 884 for (i = 0; i < nfds; i++) {
885 int revents;
886 if (((revents = pfds[i].revents) == 0) || ((fd = pfds[i].fd) == -1))
dcfe6390 887 continue;
7a974f67 888 if (fdIsHttpOrIcp(fd))
996a0a51 889 continue;
429fdbec 890 if (revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) {
a3d5953d 891 debug(5, 6) ("comm_poll: FD %d ready for reading\n", fd);
0b2421ea 892 if ((hdl = fd_table[fd].read_handler)) {
76f87348 893 fd_table[fd].read_handler = NULL;
0b2421ea 894 hdl(fd, fd_table[fd].read_data);
895 }
ba4f8e5a 896 if (commCheckIncoming)
897 comm_incoming();
dcfe6390 898 }
429fdbec 899 if (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) {
a3d5953d 900 debug(5, 5) ("comm_poll: FD %d ready for writing\n", fd);
0b2421ea 901 if ((hdl = fd_table[fd].write_handler)) {
76f87348 902 fd_table[fd].write_handler = NULL;
0b2421ea 903 hdl(fd, fd_table[fd].write_data);
904 }
ba4f8e5a 905 if (commCheckIncoming)
906 comm_incoming();
dcfe6390 907 }
429fdbec 908 if (revents & POLLNVAL) {
f1dc9b30 909 close_handler *ch;
76f87348 910 fde *F = &fd_table[fd];
a3d5953d 911 debug(5, 0) ("WARNING: FD %d has handlers, but it's invalid.\n", fd);
22f5d1ca 912 debug(5, 0) ("FD %d is a %s\n", fd, fdTypeStr[fd_table[fd].type]);
a3d5953d 913 debug(5, 0) ("--> %s\n", fd_table[fd].desc);
914 debug(5, 0) ("tmout:%p read:%p write:%p\n",
76f87348 915 F->timeout_handler,
916 F->read_handler,
917 F->write_handler);
76f87348 918 for (ch = F->close_handler; ch; ch = ch->next)
a3d5953d 919 debug(5, 0) (" close handler: %p\n", ch->handler);
76f87348 920 if (F->close_handler) {
3be3bbc6 921 commCallCloseHandlers(fd);
76f87348 922 } else if (F->timeout_handler) {
a3d5953d 923 debug(5, 0) ("comm_poll: Calling Timeout Handler\n");
76f87348 924 F->timeout_handler(fd, F->timeout_data);
dcfe6390 925 }
76f87348 926 F->close_handler = NULL;
927 F->timeout_handler = NULL;
928 F->read_handler = NULL;
929 F->write_handler = NULL;
0e473d70 930 if (F->open != 0)
6cf028ab 931 fd_close(fd);
dcfe6390 932 }
ba4f8e5a 933 lastinc = incame;
dcfe6390 934 }
935 return COMM_OK;
52040193 936 } while (timeout > current_dtime);
a3d5953d 937 debug(5, 8) ("comm_poll: time out: %d.\n", squid_curtime);
dcfe6390 938 return COMM_TIMEOUT;
055f4d4d 939}
090089c4 940
dcfe6390 941#else
090089c4 942
943/* Select on all sockets; call handlers for those that are ready. */
b8d8561b 944int
52040193 945comm_select(int msec)
090089c4 946{
090089c4 947 fd_set readfds;
948 fd_set writefds;
582b6456 949 PF *hdl = NULL;
7d49daab 950 int fd;
951 int i;
952 int maxfd;
953 int nfds;
090089c4 954 int num;
090089c4 955 static time_t last_timeout = 0;
956 struct timeval poll_time;
97c03d3c 957 static int lastinc;
52040193 958 double timeout = current_dtime + (msec / 1000.0);
090089c4 959
f7361640 960 do {
b984c445 961#if !ALARM_UPDATES_TIME
962 getCurrentTime();
963#endif
6cf028ab 964
965#if USE_ASYNC_IO
966 aioCheckCallbacks();
967#endif
968
090089c4 969 FD_ZERO(&readfds);
970 FD_ZERO(&writefds);
2681d383 971 if (shutting_down) {
30a4f2a8 972 serverConnectionsClose();
f88bb09c 973 dnsShutdownServers();
d2af9477 974 redirectShutdownServers();
2681d383 975 /* shutting_down will be set to
429fdbec 976 * +1 for SIGTERM
977 * -1 for SIGINT */
2681d383 978 if (shutting_down > 0)
5c5783a2 979 setSocketShutdownLifetimes(Config.shutdownLifetime);
f3753518 980 else
3ed6e11e 981 setSocketShutdownLifetimes(1);
30a4f2a8 982 }
ba4f8e5a 983 comm_incoming();
4d64d74a 984 nfds = 0;
429fdbec 985 maxfd = Biggest_FD + 1;
4d64d74a 986 for (i = 0; i < maxfd; i++) {
090089c4 987 /* Check each open socket for a handler. */
da2b3a17 988 if (fd_table[i].read_handler && !commDeferRead(i)) {
4d64d74a 989 nfds++;
090089c4 990 FD_SET(i, &readfds);
4d64d74a 991 }
992 if (fd_table[i].write_handler) {
993 nfds++;
090089c4 994 FD_SET(i, &writefds);
4d64d74a 995 }
090089c4 996 }
2681d383 997 if (shutting_down)
a3d5953d 998 debug(5, 2) ("comm_select: Still waiting on %d FDs\n", nfds);
4d64d74a 999 if (nfds == 0)
1000 return COMM_SHUTDOWN;
52040193 1001 if (msec > MAX_POLL_TIME)
1002 msec = MAX_POLL_TIME;
7690e8eb 1003 for (;;) {
52040193 1004 poll_time.tv_sec = msec / 1000;
1005 poll_time.tv_usec = (msec % 1000) * 1000;
d0217c9b 1006 num = select(maxfd, &readfds, &writefds, NULL, &poll_time);
f2908497 1007 Counter.select_loops++;
090089c4 1008 if (num >= 0)
1009 break;
ee264d61 1010 if (ignoreErrno(errno))
4d64d74a 1011 break;
a3d5953d 1012 debug(50, 0) ("comm_select: select failure: %s\n",
30a4f2a8 1013 xstrerror());
d0217c9b 1014 examine_select(&readfds, &writefds);
bf9f8f2b 1015 return COMM_ERROR;
30a4f2a8 1016 /* NOTREACHED */
090089c4 1017 }
4d64d74a 1018 if (num < 0)
1019 continue;
a3d5953d 1020 debug(5, num ? 5 : 8) ("comm_select: %d sockets ready at %d\n",
30a4f2a8 1021 num, (int) squid_curtime);
090089c4 1022
1023 /* Check lifetime and timeout handlers ONCE each second.
1024 * Replaces brain-dead check every time through the loop! */
b8de7ebe 1025 if (squid_curtime > last_timeout) {
1026 last_timeout = squid_curtime;
090089c4 1027 checkTimeouts();
090089c4 1028 }
7d49daab 1029 if (num == 0)
1030 continue;
1031
090089c4 1032 /* scan each socket but the accept socket. Poll this
2c5294ce 1033 * more frequently to minimize losses due to the 5 connect
090089c4 1034 * limit in SunOS */
1035
5742d7c9 1036 for (fd = 0; fd < maxfd; fd++) {
d0217c9b 1037 if (!FD_ISSET(fd, &readfds) && !FD_ISSET(fd, &writefds))
7d49daab 1038 continue;
7a974f67 1039 if (fdIsHttpOrIcp(fd))
7d49daab 1040 continue;
7d49daab 1041 if (FD_ISSET(fd, &readfds)) {
a3d5953d 1042 debug(5, 6) ("comm_select: FD %d ready for reading\n", fd);
7d49daab 1043 if (fd_table[fd].read_handler) {
ff8d0ea6 1044 hdl = fd_table[fd].read_handler;
76f87348 1045 fd_table[fd].read_handler = NULL;
ff8d0ea6 1046 hdl(fd, fd_table[fd].read_data);
090089c4 1047 }
ba4f8e5a 1048 if (commCheckIncoming)
1049 comm_incoming();
7d49daab 1050 }
1051 if (FD_ISSET(fd, &writefds)) {
a3d5953d 1052 debug(5, 5) ("comm_select: FD %d ready for writing\n", fd);
7d49daab 1053 if (fd_table[fd].write_handler) {
ff8d0ea6 1054 hdl = fd_table[fd].write_handler;
76f87348 1055 fd_table[fd].write_handler = NULL;
ff8d0ea6 1056 hdl(fd, fd_table[fd].write_data);
090089c4 1057 }
ba4f8e5a 1058 if (commCheckIncoming)
1059 comm_incoming();
7d49daab 1060 }
ba4f8e5a 1061 lastinc = incame;
090089c4 1062 }
7d49daab 1063 return COMM_OK;
52040193 1064 } while (timeout > current_dtime);
5f6ac48b 1065 debug(5, 8) ("comm_select: time out: %d\n", (int) squid_curtime);
090089c4 1066 return COMM_TIMEOUT;
1067}
dcfe6390 1068#endif
090089c4 1069
b8d8561b 1070void
582b6456 1071commSetSelect(int fd, unsigned int type, PF * handler, void *client_data, time_t timeout)
090089c4 1072{
89de058c 1073 fde *F = &fd_table[fd];
489b22c1 1074 assert(fd >= 0);
89de058c 1075 assert(F->open == FD_OPEN);
cebe3f19 1076 debug(5, 5) ("commSetSelect: FD %d type %d\n", fd, type);
090089c4 1077 if (type & COMM_SELECT_READ) {
76f87348 1078 F->read_handler = handler;
1079 F->read_data = client_data;
090089c4 1080 }
1081 if (type & COMM_SELECT_WRITE) {
76f87348 1082 F->write_handler = handler;
1083 F->write_data = client_data;
090089c4 1084 }
5c5783a2 1085 if (timeout)
76f87348 1086 F->timeout = squid_curtime + timeout;
090089c4 1087}
1088
b8d8561b 1089void
582b6456 1090comm_add_close_handler(int fd, PF * handler, void *data)
30a4f2a8 1091{
f1dc9b30 1092 close_handler *new = xmalloc(sizeof(*new));
cddc721b 1093 close_handler *c;
a3d5953d 1094 debug(5, 5) ("comm_add_close_handler: FD %d, handler=%p, data=%p\n",
e0c42e90 1095 fd, handler, data);
cddc721b 1096 for (c = fd_table[fd].close_handler; c; c=c->next)
1097 assert(c->handler != handler && c->data != data);
30a4f2a8 1098 new->handler = handler;
1099 new->data = data;
1100 new->next = fd_table[fd].close_handler;
1101 fd_table[fd].close_handler = new;
603a02fd 1102 cbdataLock(data);
30a4f2a8 1103}
1104
b8d8561b 1105void
582b6456 1106comm_remove_close_handler(int fd, PF * handler, void *data)
090089c4 1107{
f1dc9b30 1108 close_handler *p;
1109 close_handler *last = NULL;
30a4f2a8 1110 /* Find handler in list */
e869f2bd 1111 debug(5, 5) ("comm_remove_close_handler: FD %d, handler=%p, data=%p\n",
1112 fd, handler, data);
30a4f2a8 1113 for (p = fd_table[fd].close_handler; p != NULL; last = p, p = p->next)
1114 if (p->handler == handler && p->data == data)
1115 break; /* This is our handler */
f88211e8 1116 assert(p != NULL);
30a4f2a8 1117 /* Remove list entry */
1118 if (last)
1119 last->next = p->next;
1120 else
1121 fd_table[fd].close_handler = p->next;
1390960a 1122 cbdataUnlock(p->data);
30a4f2a8 1123 safe_free(p);
1124}
090089c4 1125
b8d8561b 1126static void
1127commSetNoLinger(int fd)
30a4f2a8 1128{
1129 struct linger L;
090089c4 1130 L.l_onoff = 0; /* off */
1131 L.l_linger = 0;
30a4f2a8 1132 if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &L, sizeof(L)) < 0)
a3d5953d 1133 debug(50, 0) ("commSetNoLinger: FD %d: %s\n", fd, xstrerror());
58a6c186 1134 fd_table[fd].flags.nolinger = 1;
090089c4 1135}
1136
b8d8561b 1137static void
1138commSetReuseAddr(int fd)
090089c4 1139{
1140 int on = 1;
30a4f2a8 1141 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0)
a3d5953d 1142 debug(50, 1) ("commSetReuseAddr: FD %d: %s\n", fd, xstrerror());
090089c4 1143}
1144
b8d8561b 1145static void
1146commSetTcpRcvbuf(int fd, int size)
f868539a 1147{
1148 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *) &size, sizeof(size)) < 0)
a3d5953d 1149 debug(50, 1) ("commSetTcpRcvbuf: FD %d, SIZE %d: %s\n",
b6f794d6 1150 fd, size, xstrerror());
f868539a 1151}
1152
b8d8561b 1153int
1154commSetNonBlocking(int fd)
30a4f2a8 1155{
731e4d49 1156 int flags;
9e205701 1157 int dummy = 0;
95cf2361 1158 if ((flags = fcntl(fd, F_GETFL, dummy)) < 0) {
a3d5953d 1159 debug(50, 0) ("FD %d: fcntl F_GETFL: %s\n", fd, xstrerror());
731e4d49 1160 return COMM_ERROR;
1161 }
4f92c80c 1162 if (fcntl(fd, F_SETFL, flags | SQUID_NONBLOCK) < 0) {
a3d5953d 1163 debug(50, 0) ("commSetNonBlocking: FD %d: %s\n", fd, xstrerror());
30a4f2a8 1164 return COMM_ERROR;
090089c4 1165 }
58a6c186 1166 fd_table[fd].flags.nonblocking = 1;
090089c4 1167 return 0;
1168}
1169
b8d8561b 1170void
1171commSetCloseOnExec(int fd)
3ca60c86 1172{
1173#ifdef FD_CLOEXEC
731e4d49 1174 int flags;
7a18b487 1175 int dummy = 0;
c7989865 1176 if ((flags = fcntl(fd, F_GETFL, dummy)) < 0) {
a3d5953d 1177 debug(50, 0) ("FD %d: fcntl F_GETFL: %s\n", fd, xstrerror());
24382924 1178 return;
3ca60c86 1179 }
24382924 1180 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
a3d5953d 1181 debug(50, 0) ("FD %d: set close-on-exec failed: %s\n", fd, xstrerror());
3ca60c86 1182#endif
1183}
1184
e90100aa 1185#ifdef TCP_NODELAY
1186static void
1187commSetTcpNoDelay(int fd)
1188{
1189 int on = 1;
1190 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on)) < 0)
a3d5953d 1191 debug(50, 1) ("commSetTcpNoDelay: FD %d: %s\n", fd, xstrerror());
e90100aa 1192}
1193#endif
1194
d86b3703 1195void
0673c0ba 1196comm_init(void)
090089c4 1197{
309ad3b6 1198 int i;
f1dc9b30 1199 fd_table = xcalloc(Squid_MaxFD, sizeof(fde));
59c4d35b 1200 /* XXX account fd_table */
090089c4 1201 /* Keep a few file descriptors free so that we don't run out of FD's
1202 * after accepting a client but before it opens a socket or a file.
e83892e9 1203 * Since Squid_MaxFD can be as high as several thousand, don't waste them */
0254ee29 1204 RESERVED_FD = XMIN(100, Squid_MaxFD / 4);
055f4d4d 1205 zero_tv.tv_sec = 0;
1206 zero_tv.tv_usec = 0;
309ad3b6 1207 invert32[0] = 32;
1208 for (i = 1; i < INCOMING_TOTAL_MAX; i++)
1209 invert32[i] = (int) (32.0 / (double) i + 0.5);
1210 cachemgrRegister("comm_incoming",
1211 "comm_incoming() stats",
1212 commIncomingStats, 0);
090089c4 1213}
1214
1215
f88211e8 1216#if !HAVE_POLL
090089c4 1217/*
1218 * examine_select - debug routine.
1219 *
1220 * I spend the day chasing this core dump that occurs when both the client
1221 * and the server side of a cache fetch simultaneoulsy abort the
1222 * connection. While I haven't really studied the code to figure out how
1223 * it happens, the snippet below may prevent the cache from exitting:
1224 *
1225 * Call this from where the select loop fails.
1226 */
b8d8561b 1227static int
5742d7c9 1228examine_select(fd_set * readfds, fd_set * writefds)
090089c4 1229{
1230 int fd = 0;
bbc5ea8f 1231 fd_set read_x;
1232 fd_set write_x;
090089c4 1233 int num;
1234 struct timeval tv;
f1dc9b30 1235 close_handler *ch = NULL;
76f87348 1236 fde *F = NULL;
090089c4 1237
a3d5953d 1238 debug(5, 0) ("examine_select: Examining open file descriptors...\n");
e83892e9 1239 for (fd = 0; fd < Squid_MaxFD; fd++) {
090089c4 1240 FD_ZERO(&read_x);
1241 FD_ZERO(&write_x);
090089c4 1242 tv.tv_sec = tv.tv_usec = 0;
af00901c 1243 if (FD_ISSET(fd, readfds))
090089c4 1244 FD_SET(fd, &read_x);
af00901c 1245 else if (FD_ISSET(fd, writefds))
1246 FD_SET(fd, &write_x);
af00901c 1247 else
1248 continue;
e83892e9 1249 num = select(Squid_MaxFD, &read_x, &write_x, NULL, &tv);
af00901c 1250 if (num > -1) {
a3d5953d 1251 debug(5, 5) ("FD %d is valid.\n", fd);
af00901c 1252 continue;
1253 }
76f87348 1254 F = &fd_table[fd];
a3d5953d 1255 debug(5, 0) ("FD %d: %s\n", fd, xstrerror());
1256 debug(5, 0) ("WARNING: FD %d has handlers, but it's invalid.\n", fd);
1257 debug(5, 0) ("FD %d is a %s called '%s'\n",
ca98227c 1258 fd,
22f5d1ca 1259 fdTypeStr[fd_table[fd].type],
76f87348 1260 F->desc);
a3d5953d 1261 debug(5, 0) ("tmout:%p read:%p write:%p\n",
76f87348 1262 F->timeout_handler,
1263 F->read_handler,
1264 F->write_handler);
1265 for (ch = F->close_handler; ch; ch = ch->next)
a3d5953d 1266 debug(5, 0) (" close handler: %p\n", ch->handler);
76f87348 1267 if (F->close_handler) {
3be3bbc6 1268 commCallCloseHandlers(fd);
76f87348 1269 } else if (F->timeout_handler) {
a3d5953d 1270 debug(5, 0) ("examine_select: Calling Timeout Handler\n");
76f87348 1271 F->timeout_handler(fd, F->timeout_data);
090089c4 1272 }
76f87348 1273 F->close_handler = NULL;
1274 F->timeout_handler = NULL;
1275 F->read_handler = NULL;
1276 F->write_handler = NULL;
af00901c 1277 FD_CLR(fd, readfds);
1278 FD_CLR(fd, writefds);
090089c4 1279 }
090089c4 1280 return 0;
1281}
dcfe6390 1282#endif
090089c4 1283
b8d8561b 1284static void
0673c0ba 1285checkTimeouts(void)
090089c4 1286{
1287 int fd;
76f87348 1288 fde *F = NULL;
5c5783a2 1289 PF *callback;
429fdbec 1290 for (fd = 0; fd <= Biggest_FD; fd++) {
76f87348 1291 F = &fd_table[fd];
1292 if (F->open != FD_OPEN)
429fdbec 1293 continue;
76f87348 1294 if (F->timeout == 0)
30a4f2a8 1295 continue;
76f87348 1296 if (F->timeout > squid_curtime)
30a4f2a8 1297 continue;
a3d5953d 1298 debug(5, 5) ("checkTimeouts: FD %d Expired\n", fd);
76f87348 1299 if (F->timeout_handler) {
a3d5953d 1300 debug(5, 5) ("checkTimeouts: FD %d: Call timeout handler\n", fd);
76f87348 1301 callback = F->timeout_handler;
1302 F->timeout_handler = NULL;
1303 callback(fd, F->timeout_data);
30a4f2a8 1304 } else {
a3d5953d 1305 debug(5, 5) ("checkTimeouts: FD %d: Forcing comm_close()\n", fd);
30a4f2a8 1306 comm_close(fd);
090089c4 1307 }
1308 }
1309}
1310
30a4f2a8 1311/* Write to FD. */
b8d8561b 1312static void
582b6456 1313commHandleWrite(int fd, void *data)
30a4f2a8 1314{
f17936ab 1315 CommWriteStateData *state = data;
30a4f2a8 1316 int len = 0;
1317 int nleft;
1318
cebe3f19 1319 debug(5, 5) ("commHandleWrite: FD %d: off %d, sz %d.\n",
5f6ac48b 1320 fd, (int) state->offset, state->size);
30a4f2a8 1321
1322 nleft = state->size - state->offset;
1323 len = write(fd, state->buf + state->offset, nleft);
c07aed63 1324 debug(5,5)("commHandleWrite: write() returns %d\n", len);
b69f7771 1325 fd_bytes(fd, len, FD_WRITE);
30a4f2a8 1326
1327 if (len == 0) {
1328 /* Note we even call write if nleft == 0 */
1329 /* We're done */
1330 if (nleft != 0)
02be0294 1331 debug(5, 1) ("commHandleWrite: FD %d: write failure: connection closed with %d bytes remaining.\n", fd, nleft);
f17936ab 1332 CommWriteStateCallbackAndFree(fd, nleft ? COMM_ERROR : COMM_OK);
30a4f2a8 1333 } else if (len < 0) {
1334 /* An error */
26a880e2 1335 if (ignoreErrno(errno)) {
a3d5953d 1336 debug(50, 10) ("commHandleWrite: FD %d: write failure: %s.\n",
30a4f2a8 1337 fd, xstrerror());
b177367b 1338 commSetSelect(fd,
30a4f2a8 1339 COMM_SELECT_WRITE,
cd1fb0eb 1340 commHandleWrite,
b177367b 1341 state,
85d7ea98 1342 0);
9864ee44 1343 } else {
a3d5953d 1344 debug(50, 2) ("commHandleWrite: FD %d: write failure: %s.\n",
9864ee44 1345 fd, xstrerror());
f17936ab 1346 CommWriteStateCallbackAndFree(fd, COMM_ERROR);
30a4f2a8 1347 }
30a4f2a8 1348 } else {
1349 /* A successful write, continue */
1350 state->offset += len;
1351 if (state->offset < state->size) {
1352 /* Not done, reinstall the write handler and write some more */
b177367b 1353 commSetSelect(fd,
30a4f2a8 1354 COMM_SELECT_WRITE,
cd1fb0eb 1355 commHandleWrite,
b177367b 1356 state,
85d7ea98 1357 0);
9864ee44 1358 } else {
f17936ab 1359 CommWriteStateCallbackAndFree(fd, COMM_OK);
30a4f2a8 1360 }
30a4f2a8 1361 }
1362}
1363
1364
1365
1366/* Select for Writing on FD, until SIZE bytes are sent. Call
1367 * * HANDLER when complete. */
b8d8561b 1368void
9e4ad609 1369comm_write(int fd, char *buf, int size, CWCB * handler, void *handler_data, FREE * free_func)
30a4f2a8 1370{
aa9e2cab 1371 CommWriteStateData *state = fd_table[fd].rwstate;
a3d5953d 1372 debug(5, 5) ("comm_write: FD %d: sz %d: hndl %p: data %p.\n",
787869c5 1373 fd, size, handler, handler_data);
aa9e2cab 1374 if (NULL != state) {
afde8a9d 1375 debug(5, 1) ("comm_write: fd_table[%d].rwstate != NULL\n", fd);
aa9e2cab 1376 safe_free(state);
6cf028ab 1377 fd_table[fd].rwstate = NULL;
1378 }
aa9e2cab 1379 assert(state == NULL);
1380 fd_table[fd].rwstate = state = xcalloc(1, sizeof(CommWriteStateData));
30a4f2a8 1381 state->buf = buf;
1382 state->size = size;
1383 state->offset = 0;
1384 state->handler = handler;
30a4f2a8 1385 state->handler_data = handler_data;
c0dec081 1386 state->free_func = free_func;
1a8f5ed6 1387 cbdataLock(handler_data);
aa9e2cab 1388 commSetSelect(fd, COMM_SELECT_WRITE, commHandleWrite, state, 0);
30a4f2a8 1389}
26a880e2 1390
137ee196 1391/* a wrapper around comm_write to allow for MemBuf to be comm_written in a snap */
cb69b4c7 1392void
1393comm_write_mbuf(int fd, MemBuf mb, CWCB * handler, void *handler_data)
1394{
1395 comm_write(fd, mb.buf, mb.size, handler, handler_data, memBufFreeFunc(&mb));
1396}
1397
89924214 1398/*
1399 * hm, this might be too general-purpose for all the places we'd
1400 * like to use it.
1401 */
b224ea98 1402int
edd2eb63 1403ignoreErrno(int ierrno)
26a880e2 1404{
603500e7 1405 switch (ierrno) {
89924214 1406 case EINPROGRESS:
603500e7 1407 case EWOULDBLOCK:
26a880e2 1408#if EAGAIN != EWOULDBLOCK
603500e7 1409 case EAGAIN:
26a880e2 1410#endif
603500e7 1411 case EALREADY:
1412 case EINTR:
db494ab8 1413#ifdef ERESTART
1414 case ERESTART:
1415#endif
26a880e2 1416 return 1;
603500e7 1417 default:
1418 return 0;
1419 }
1420 /* NOTREACHED */
26a880e2 1421}
309ad3b6 1422
1423static void
1424commIncomingStats(StoreEntry * sentry)
1425{
1426 StatCounters *f = &Counter;
1427 storeAppendPrintf(sentry, "Current incoming_interval: %d\n",
1428 incoming_interval >> 4);
1429 storeAppendPrintf(sentry, "\n");
1430 storeAppendPrintf(sentry, "Histogram of number of incoming sockets or\n");
1431 storeAppendPrintf(sentry, "Messages handled per comm_incoming() call:\n");
1432 statHistDump(&f->comm_incoming, sentry, statHistIntDumper);
1433}