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