]> git.ipfire.org Git - thirdparty/squid.git/blame - src/comm.cc
call clientWriteComplete so the client socket gets closed
[thirdparty/squid.git] / src / comm.cc
CommitLineData
da2b3a17 1
30a4f2a8 2/*
e1b16349 3 * $Id: comm.cc,v 1.238 1998/03/27 19:42:22 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;
e1b16349 360 commSetTimeout(fd, -1, NULL, NULL);
a3d5953d 361 commConnectFree(fd, cs);
8407afee 362 if (cbdataValid(data))
365e5b34 363 callback(fd, status, data);
1790d392 364 cbdataUnlock(data);
f88211e8 365}
366
e924600d 367static void
9daca08e 368commConnectFree(int fd, void *data)
e924600d 369{
370 ConnectStateData *cs = data;
9daca08e 371 debug(5, 3) ("commConnectFree: FD %d\n", fd);
8407afee 372 if (cs->locks)
365e5b34 373 ipcacheUnregister(cs->host, cs);
9daca08e 374 if (cs->data)
375 cbdataUnlock(cs->data);
8407afee 376 safe_free(cs->host);
377 cbdataFree(cs);
e924600d 378}
379
22c653cd 380/* Reset FD so that we can connect() again */
edeb28fd 381static int
22c653cd 382commResetFD(ConnectStateData * cs)
edeb28fd 383{
384 int fd2;
7dd44885 385 if (!cbdataValid(cs->data))
386 return 0;
edeb28fd 387 fd2 = socket(AF_INET, SOCK_STREAM, 0);
388 if (fd2 < 0) {
22c653cd 389 debug(5, 0) ("commResetFD: socket: %s\n", xstrerror());
4b23e114 390 fdAdjustReserved();
edeb28fd 391 return 0;
392 }
22c653cd 393 if (dup2(fd2, cs->fd) < 0) {
394 debug(5, 0) ("commResetFD: dup2: %s\n", xstrerror());
4b23e114 395 fdAdjustReserved();
edeb28fd 396 return 0;
397 }
edeb28fd 398 close(fd2);
79d39a72 399 commSetConnectTimeout(cs->fd, commBackoffTimeout((int) cs->addrcount));
22c653cd 400 commSetNonBlocking(cs->fd);
edeb28fd 401 return 1;
402}
403
22c653cd 404static int
405commRetryConnect(ConnectStateData * cs)
406{
407 assert(cs->addrcount > 0);
408 if (cs->addrcount == 1) {
409 if (cs->tries >= Config.retry.maxtries)
410 return 0;
411 if (squid_curtime - cs->connstart > Config.Timeout.connect)
412 return 0;
79d39a72 413 commSetConnectTimeout(cs->fd, commBackoffTimeout(100));
22c653cd 414 } else {
415 if (cs->tries > cs->addrcount)
416 return 0;
417 }
418 return commResetFD(cs);
419}
420
421/* Back off the socket timeout if there are several addresses available */
422static time_t
79d39a72 423commBackoffTimeout(int numaddrs)
22c653cd 424{
425 time_t timeout;
426 timeout = (time_t) Config.Timeout.connect;
427 if (numaddrs > 2) {
428 timeout = (time_t) (Config.Timeout.connect / numaddrs);
429 if (timeout < Config.retry.timeout)
430 timeout = (time_t) Config.retry.timeout;
431 }
432 return timeout;
433}
434
e924600d 435/* Connect SOCK to specified DEST_PORT at DEST_HOST. */
436static void
437commConnectHandle(int fd, void *data)
090089c4 438{
f88211e8 439 ConnectStateData *cs = data;
440 if (cs->S.sin_addr.s_addr == 0) {
441 cs->S.sin_family = AF_INET;
442 cs->S.sin_addr = cs->in_addr;
443 cs->S.sin_port = htons(cs->port);
17a0a4ee 444 if (Config.onoff.log_fqdn)
f88211e8 445 fqdncache_gethostbyaddr(cs->S.sin_addr, FQDN_LOOKUP_IF_MISS);
e5f6c5c2 446 }
f88211e8 447 switch (comm_connect_addr(fd, &cs->S)) {
e5f6c5c2 448 case COMM_INPROGRESS:
11994bb9 449 debug(5, 5) ("commConnectHandle: FD %d: COMM_INPROGRESS\n", fd);
f88211e8 450 commSetSelect(fd, COMM_SELECT_WRITE, commConnectHandle, cs, 0);
e5f6c5c2 451 break;
452 case COMM_OK:
22c653cd 453 ipcacheMarkGoodAddr(cs->host, cs->S.sin_addr);
03a1ee42 454 commConnectCallback(cs, COMM_OK);
e5f6c5c2 455 break;
456 default:
22c653cd 457 cs->tries++;
458 ipcacheMarkBadAddr(cs->host, cs->S.sin_addr);
194dd3b8 459 if (Config.onoff.test_reachability)
460 netdbDeleteAddrNetwork(cs->S.sin_addr);
22c653cd 461 if (commRetryConnect(cs)) {
f88211e8 462 cs->locks++;
8407afee 463 ipcache_nbgethostbyname(cs->host, commConnectDnsHandle, cs);
edeb28fd 464 } else {
03a1ee42 465 commConnectCallback(cs, COMM_ERR_CONNECT);
edeb28fd 466 }
e5f6c5c2 467 break;
090089c4 468 }
090089c4 469}
22c653cd 470
b8d8561b 471int
4f92c80c 472commSetTimeout(int fd, int timeout, PF * handler, void *data)
090089c4 473{
76f87348 474 fde *F;
a3d5953d 475 debug(5, 3) ("commSetTimeout: FD %d timeout %d\n", fd, timeout);
03eb2f01 476 assert(fd >= 0);
477 assert(fd < Squid_MaxFD);
76f87348 478 F = &fd_table[fd];
0ca54a51 479 assert(F->open);
5c5783a2 480 if (timeout < 0) {
76f87348 481 F->timeout_handler = NULL;
482 F->timeout_data = NULL;
483 return F->timeout = 0;
5c5783a2 484 }
bbdb774b 485 if (shutdown_pending || reconfigure_pending) {
4f92c80c 486 /* don't increase the timeout if something pending */
76f87348 487 if (F->timeout > 0 && (int) (F->timeout - squid_curtime) < timeout)
488 return F->timeout;
5c5783a2 489 }
76f87348 490 assert(handler || F->timeout_handler);
5c5783a2 491 if (handler || data) {
76f87348 492 F->timeout_handler = handler;
493 F->timeout_data = data;
30a4f2a8 494 }
76f87348 495 return F->timeout = squid_curtime + (time_t) timeout;
090089c4 496}
497
b8d8561b 498int
0ee4272b 499comm_connect_addr(int sock, const struct sockaddr_in *address)
090089c4 500{
501 int status = COMM_OK;
76f87348 502 fde *F = &fd_table[sock];
090089c4 503 int len;
504 int x;
489b22c1 505 assert(ntohs(address->sin_port) != 0);
090089c4 506 /* Establish connection. */
086bce16 507 if (connect(sock, (struct sockaddr *) address, sizeof(struct sockaddr_in)) < 0) {
365e5b34 508 debug(5, 9) ("connect FD %d: %s\n", sock, xstrerror());
090089c4 509 switch (errno) {
510 case EALREADY:
f81b2bec 511#ifdef _SQUID_HPUX_
512 /*
513 * On my HP-UX box (HP-UX tirana B.10.10 A 9000/851),
514 * we get into fast loops on EALREADY. select(2) continually
515 * says the FD is ready for writing, but connect always
516 * returns EALREADY. I applied a patch (PHNE_12906) but
164f7660 517 * it didn't help. -DW Dec 1, 1997
f81b2bec 518 */
519 debug(50, 1) ("connect: %s:%d: %s.\n",
520 fqdnFromAddr(address->sin_addr),
521 ntohs(address->sin_port),
522 xstrerror());
523 return COMM_ERROR;
524 /* NOTREACHEd */
525#endif
30a4f2a8 526#if EAGAIN != EWOULDBLOCK
527 case EAGAIN:
528#endif
0a0bf5db 529 case EINTR:
30a4f2a8 530 case EWOULDBLOCK:
090089c4 531 case EINPROGRESS:
e5f6c5c2 532 status = COMM_INPROGRESS;
090089c4 533 break;
534 case EISCONN:
535 status = COMM_OK;
536 break;
537 case EINVAL:
538 len = sizeof(x);
539 if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *) &x, &len) >= 0)
540 errno = x;
541 default:
a3d5953d 542 debug(50, 2) ("connect: %s:%d: %s.\n",
28ab0c0a 543 fqdnFromAddr(address->sin_addr),
090089c4 544 ntohs(address->sin_port),
545 xstrerror());
546 return COMM_ERROR;
547 }
e5f6c5c2 548 }
76f87348 549 xstrncpy(F->ipaddr, inet_ntoa(address->sin_addr), 16);
550 F->remote_port = ntohs(address->sin_port);
090089c4 551 if (status == COMM_OK) {
a3d5953d 552 debug(5, 10) ("comm_connect_addr: FD %d connected to %s:%d\n",
76f87348 553 sock, F->ipaddr, F->remote_port);
f21cd581 554 } else if (status == COMM_INPROGRESS) {
a3d5953d 555 debug(5, 10) ("comm_connect_addr: FD %d connection pending\n", sock);
090089c4 556 }
557 /* Add new socket to list of open sockets. */
090089c4 558 return status;
559}
560
561/* Wait for an incoming connection on FD. FD should be a socket returned
562 * from comm_listen. */
b8d8561b 563int
564comm_accept(int fd, struct sockaddr_in *peer, struct sockaddr_in *me)
090089c4 565{
566 int sock;
1f9afe33 567 struct sockaddr_in P;
568 struct sockaddr_in M;
090089c4 569 int Slen;
76f87348 570 fde *F = NULL;
090089c4 571
1f9afe33 572 Slen = sizeof(P);
573 while ((sock = accept(fd, (struct sockaddr *) &P, &Slen)) < 0) {
090089c4 574 switch (errno) {
575#if EAGAIN != EWOULDBLOCK
576 case EAGAIN:
577#endif
578 case EWOULDBLOCK:
090089c4 579 case EINTR:
0a0bf5db 580 return COMM_NOMESSAGE;
090089c4 581 case ENFILE:
582 case EMFILE:
090089c4 583 return COMM_ERROR;
584 default:
a3d5953d 585 debug(50, 1) ("comm_accept: FD %d: accept failure: %s\n",
090089c4 586 fd, xstrerror());
587 return COMM_ERROR;
588 }
79d39a72 589 /* NOTREACHED */
090089c4 590 }
591
592 if (peer)
1f9afe33 593 *peer = P;
4053a845 594 Slen = sizeof(M);
595 memset(&M, '\0', Slen);
596 getsockname(sock, (struct sockaddr *) &M, &Slen);
597 if (me)
1f9afe33 598 *me = M;
3ca60c86 599 commSetCloseOnExec(sock);
090089c4 600 /* fdstat update */
5c5783a2 601 fd_open(sock, FD_SOCKET, "HTTP Request");
76f87348 602 F = &fd_table[sock];
c0dec081 603 xstrncpy(F->ipaddr, inet_ntoa(P.sin_addr), 16);
76f87348 604 F->remote_port = htons(P.sin_port);
605 F->local_port = htons(M.sin_port);
090089c4 606 commSetNonBlocking(sock);
090089c4 607 return sock;
608}
609
cb201b7e 610void
611commCallCloseHandlers(int fd)
612{
76f87348 613 fde *F = &fd_table[fd];
f1dc9b30 614 close_handler *ch;
a3d5953d 615 debug(5, 5) ("commCallCloseHandlers: FD %d\n", fd);
76f87348 616 while ((ch = F->close_handler) != NULL) {
617 F->close_handler = ch->next;
9daca08e 618 debug(5, 5) ("commCallCloseHandlers: ch->handler=%p\n", ch->handler);
603a02fd 619 if (cbdataValid(ch->data))
620 ch->handler(fd, ch->data);
621 cbdataUnlock(ch->data);
cb201b7e 622 safe_free(ch);
623 }
624}
625
b8d8561b 626void
627comm_close(int fd)
090089c4 628{
76f87348 629 fde *F = NULL;
a3d5953d 630 debug(5, 5) ("comm_close: FD %d\n", fd);
03eb2f01 631 assert(fd >= 0);
632 assert(fd < Squid_MaxFD);
76f87348 633 F = &fd_table[fd];
79a15e0a 634 if (EBIT_TEST(F->flags, FD_CLOSING))
e102ebda 635 return;
0e473d70 636 if (shutdown_pending && (!F->open || F->type == FD_FILE))
6cf028ab 637 return;
b716a8ad 638 assert(F->open);
76f87348 639 assert(F->type != FD_FILE);
79a15e0a 640 EBIT_SET(F->flags, FD_CLOSING);
96f1be5d 641 CommWriteStateCallbackAndFree(fd, COMM_ERR_CLOSING);
cb201b7e 642 commCallCloseHandlers(fd);
b716a8ad 643 if (F->uses) /* assume persistent connect count */
644 pconnHistCount(1, F->uses);
5c5783a2 645 fd_close(fd); /* update fdstat */
5874bf28 646#if defined(_SQUID_LINUX_)
647 /*
648 * michael@metal.iinet.net.au sez close() on
649 * network sockets never blocks.
650 */
651 close(fd);
652#elsif USE_ASYNC_IO
0a0bf5db 653 aioClose(fd);
654#else
9864ee44 655 close(fd);
0a0bf5db 656#endif
090089c4 657}
658
090089c4 659/* Send a udp datagram to specified TO_ADDR. */
b8d8561b 660int
5df61230 661comm_udp_sendto(int fd,
662 const struct sockaddr_in *to_addr,
663 int addr_len,
664 const char *buf,
665 int len)
090089c4 666{
5df61230 667 int x;
668 x = sendto(fd, buf, len, 0, (struct sockaddr *) to_addr, addr_len);
669 if (x < 0) {
a3d5953d 670 debug(50, 1) ("comm_udp_sendto: FD %d, %s, port %d: %s\n",
5df61230 671 fd,
672 inet_ntoa(to_addr->sin_addr),
673 (int) htons(to_addr->sin_port),
674 xstrerror());
090089c4 675 return COMM_ERROR;
676 }
5df61230 677 return x;
090089c4 678}
679
b8d8561b 680void
70a9dab4 681commSetDefer(int fd, DEFER * func, void *data)
4883993a 682{
da2b3a17 683 fde *F = &fd_table[fd];
684 F->defer_check = func;
70a9dab4 685 F->defer_data = data;
4883993a 686}
687
da2b3a17 688static int
689commDeferRead(int fd)
690{
691 fde *F = &fd_table[fd];
692 if (F->defer_check == NULL)
693 return 0;
70a9dab4 694 return F->defer_check(fd, F->defer_data);
da2b3a17 695}
dcfe6390 696
f88211e8 697#if HAVE_POLL
dcfe6390 698
699/* poll() version by:
700 * Stewart Forster <slf@connect.com.au>, and
701 * Anthony Baxter <arb@connect.com.au> */
702
703static void
812ed90c 704comm_poll_incoming(void)
dcfe6390 705{
429fdbec 706 int fd;
996a0a51 707 int fds[4];
0b2421ea 708 struct pollfd pfds[3 + MAXHTTPPORTS];
996a0a51 709 unsigned long N = 0;
429fdbec 710 unsigned long i, nfds;
812ed90c 711 int j;
582b6456 712 PF *hdl = NULL;
97c03d3c 713 polledinc = 0;
dcfe6390 714 if (theInIcpConnection >= 0)
715 fds[N++] = theInIcpConnection;
933c6d93 716 if (theInIcpConnection != theOutIcpConnection)
1793867a 717 if (theOutIcpConnection >= 0)
933c6d93 718 fds[N++] = theOutIcpConnection;
0b2421ea 719 for (j = 0; j < NHttpSockets; j++) {
812ed90c 720 if (HttpSockets[j] < 0)
0b2421ea 721 continue;
da2b3a17 722 if (commDeferRead(HttpSockets[j]))
0b2421ea 723 continue;
812ed90c 724 fds[N++] = HttpSockets[j];
725 }
429fdbec 726 for (i = nfds = 0; i < N; i++) {
727 int events;
dcfe6390 728 fd = fds[i];
429fdbec 729 events = 0;
730 if (fd_table[fd].read_handler)
731 events |= POLLRDNORM;
732 if (fd_table[fd].write_handler)
733 events |= POLLWRNORM;
734 if (events) {
735 pfds[nfds].fd = fd;
736 pfds[nfds].events = events;
737 pfds[nfds].revents = 0;
738 nfds++;
dcfe6390 739 }
dcfe6390 740 }
429fdbec 741 if (!nfds)
742 return;
dc835977 743#if !ALARM_UPDATES_TIME
744 getCurrentTime();
745#endif
97c03d3c 746 polledinc = poll(pfds, nfds, 0);
747 if (polledinc < 1) {
748 polledinc = 0;
996a0a51 749 return;
97c03d3c 750 }
429fdbec 751 for (i = 0; i < nfds; i++) {
752 int revents;
753 if (((revents = pfds[i].revents) == 0) || ((fd = pfds[i].fd) == -1))
dcfe6390 754 continue;
429fdbec 755 if (revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) {
0e473d70 756 if (hdl = fd_table[fd].read_handler) {
6cf028ab 757 fd_table[fd].read_handler = NULL;
758 hdl(fd, fd_table[fd].read_data);
759 } else
0e473d70 760 debug(5, 1) ("comm_poll_incoming: NULL read handler\n");
dcfe6390 761 }
429fdbec 762 if (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) {
0e473d70 763 if (hdl = fd_table[fd].write_handler) {
6cf028ab 764 fd_table[fd].write_handler = NULL;
765 hdl(fd, fd_table[fd].write_data);
766 } else
0e473d70 767 debug(5, 1) ("comm_poll_incoming: NULL write handler\n");
dcfe6390 768 }
769 }
770 /* TO FIX: repoll ICP connection here */
771}
772
ca98227c 773#else
dcfe6390 774
b8d8561b 775static void
0673c0ba 776comm_select_incoming(void)
055f4d4d 777{
778 fd_set read_mask;
779 fd_set write_mask;
780 int maxfd = 0;
781 int fd = 0;
0b2421ea 782 int fds[3 + MAXHTTPPORTS];
055f4d4d 783 int N = 0;
784 int i = 0;
582b6456 785 PF *hdl = NULL;
97c03d3c 786 polledinc = 0;
055f4d4d 787 FD_ZERO(&read_mask);
788 FD_ZERO(&write_mask);
0b2421ea 789 for (i = 0; i < NHttpSockets; i++) {
812ed90c 790 if (HttpSockets[i] < 0)
0b2421ea 791 continue;
da2b3a17 792 if (commDeferRead(HttpSockets[i]))
0b2421ea 793 continue;
812ed90c 794 fds[N++] = HttpSockets[i];
795 }
30a4f2a8 796 if (theInIcpConnection >= 0)
797 fds[N++] = theInIcpConnection;
933c6d93 798 if (theInIcpConnection != theOutIcpConnection)
799 if (theOutIcpConnection >= 0)
800 fds[N++] = theOutIcpConnection;
055f4d4d 801 fds[N++] = 0;
055f4d4d 802 for (i = 0; i < N; i++) {
803 fd = fds[i];
804 if (fd_table[fd].read_handler) {
805 FD_SET(fd, &read_mask);
806 if (fd > maxfd)
807 maxfd = fd;
808 }
809 if (fd_table[fd].write_handler) {
810 FD_SET(fd, &write_mask);
811 if (fd > maxfd)
812 maxfd = fd;
813 }
814 }
055f4d4d 815 if (maxfd++ == 0)
816 return;
dc835977 817#if !ALARM_UPDATES_TIME
818 getCurrentTime();
819#endif
97c03d3c 820 polledinc = select(maxfd, &read_mask, &write_mask, NULL, &zero_tv);
821 if (polledinc < 1) {
822 polledinc = 0;
dcfe6390 823 return;
97c03d3c 824 }
dcfe6390 825 for (i = 0; i < N; i++) {
826 fd = fds[i];
827 if (FD_ISSET(fd, &read_mask)) {
0e473d70 828 if ((hdl = fd_table[fd].read_handler) != NULL) {
6cf028ab 829 fd_table[fd].read_handler = NULL;
830 hdl(fd, fd_table[fd].read_data);
831 } else {
0e473d70 832 debug(5, 1) ("comm_select_incoming: NULL read handler\n");
6cf028ab 833 }
dcfe6390 834 }
835 if (FD_ISSET(fd, &write_mask)) {
0e473d70 836 if ((hdl = fd_table[fd].write_handler) != NULL) {
6cf028ab 837 fd_table[fd].write_handler = NULL;
838 hdl(fd, fd_table[fd].write_data);
839 } else {
0e473d70 840 debug(5, 1) ("comm_select_incoming: NULL write handler\n");
6cf028ab 841 }
dcfe6390 842 }
843 }
844}
845#endif
846
812ed90c 847static int
848fdIsHttpOrIcp(int fd)
849{
850 int j;
851 if (fd == theInIcpConnection)
852 return 1;
853 if (fd == theOutIcpConnection)
854 return 1;
855 for (j = 0; j < NHttpSockets; j++) {
856 if (fd == HttpSockets[j])
857 return 1;
858 }
859 return 0;
860}
861
f88211e8 862#if HAVE_POLL
dcfe6390 863/* poll all sockets; call handlers for those that are ready. */
864int
812ed90c 865comm_poll(time_t sec)
dcfe6390 866{
0a0bf5db 867 struct pollfd pfds[SQUID_MAXFD];
582b6456 868 PF *hdl = NULL;
dcfe6390 869 int fd;
870 int i;
871 int maxfd;
996a0a51 872 unsigned long nfds;
dcfe6390 873 int num;
dcfe6390 874 static time_t last_timeout = 0;
97c03d3c 875 static int lastinc = 0;
429fdbec 876 int poll_time;
812ed90c 877 static int incoming_counter = 0;
dcfe6390 878 time_t timeout;
dcfe6390 879 timeout = squid_curtime + sec;
880 do {
b984c445 881#if !ALARM_UPDATES_TIME
882 getCurrentTime();
883#endif
80a7ba7f 884 if (shutdown_pending) {
dcfe6390 885 serverConnectionsClose();
dcfe6390 886 dnsShutdownServers();
887 redirectShutdownServers();
429fdbec 888 /* shutdown_pending will be set to
889 * +1 for SIGTERM
890 * -1 for SIGINT */
bbdb774b 891 /* reconfigure_pending always == 1 when SIGHUP received */
892 if (shutdown_pending > 0 || reconfigure_pending > 0)
5c5783a2 893 setSocketShutdownLifetimes(Config.shutdownLifetime);
dcfe6390 894 else
9e4ad609 895 setSocketShutdownLifetimes(1);
dcfe6390 896 }
6cf028ab 897#if USE_ASYNC_IO
898 aioCheckCallbacks();
899#endif
7a974f67 900 comm_poll_incoming();
429fdbec 901 nfds = 0;
902 maxfd = Biggest_FD + 1;
429fdbec 903 for (i = 0; i < maxfd; i++) {
904 int events;
905 events = 0;
dcfe6390 906 /* Check each open socket for a handler. */
da2b3a17 907 if (fd_table[i].read_handler && !commDeferRead(i))
429fdbec 908 events |= POLLRDNORM;
909 if (fd_table[i].write_handler)
910 events |= POLLWRNORM;
911 if (events) {
429fdbec 912 pfds[nfds].fd = i;
913 pfds[nfds].events = events;
914 pfds[nfds].revents = 0;
915 nfds++;
055f4d4d 916 }
0b2421ea 917 }
bbdb774b 918 if (shutdown_pending || reconfigure_pending)
a3d5953d 919 debug(5, 2) ("comm_poll: Still waiting on %d FDs\n", nfds);
dcfe6390 920 if (nfds == 0)
921 return COMM_SHUTDOWN;
0a0bf5db 922#if USE_ASYNC_IO
69b63e70 923 poll_time = sec > 0 ? 50 : 0;
69b63e70 924#else
925 poll_time = sec > 0 ? 1000 : 0;
0a0bf5db 926#endif
dcfe6390 927 for (;;) {
429fdbec 928 num = poll(pfds, nfds, poll_time);
f2908497 929 Counter.select_loops++;
dcfe6390 930 if (num >= 0)
931 break;
932 if (errno == EINTR)
0a0bf5db 933 continue;
a3d5953d 934 debug(5, 0) ("comm_poll: poll failure: %s\n", xstrerror());
03eb2f01 935 assert(errno != EINVAL);
dcfe6390 936 return COMM_ERROR;
937 /* NOTREACHED */
938 }
a3d5953d 939 debug(5, num ? 5 : 8) ("comm_poll: %d sockets ready\n", num);
5c5783a2 940 /* Check timeout handlers ONCE each second. */
dcfe6390 941 if (squid_curtime > last_timeout) {
942 last_timeout = squid_curtime;
943 checkTimeouts();
dcfe6390 944 }
945 if (num == 0)
946 continue;
947 /* scan each socket but the accept socket. Poll this
2c5294ce 948 * more frequently to minimize losses due to the 5 connect
dcfe6390 949 * limit in SunOS */
429fdbec 950 for (i = 0; i < nfds; i++) {
951 int revents;
952 if (((revents = pfds[i].revents) == 0) || ((fd = pfds[i].fd) == -1))
dcfe6390 953 continue;
7a974f67 954 if (fdIsHttpOrIcp(fd))
996a0a51 955 continue;
429fdbec 956 if (revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) {
a3d5953d 957 debug(5, 6) ("comm_poll: FD %d ready for reading\n", fd);
0b2421ea 958 if ((hdl = fd_table[fd].read_handler)) {
76f87348 959 fd_table[fd].read_handler = NULL;
0b2421ea 960 hdl(fd, fd_table[fd].read_data);
961 }
7a974f67 962 if ((++incoming_counter & 15) == 0)
963 comm_poll_incoming();
dcfe6390 964 }
429fdbec 965 if (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) {
a3d5953d 966 debug(5, 5) ("comm_poll: FD %d ready for writing\n", fd);
0b2421ea 967 if ((hdl = fd_table[fd].write_handler)) {
76f87348 968 fd_table[fd].write_handler = NULL;
0b2421ea 969 hdl(fd, fd_table[fd].write_data);
970 }
7a974f67 971 if ((++incoming_counter & 15) == 0)
972 comm_poll_incoming();
dcfe6390 973 }
429fdbec 974 if (revents & POLLNVAL) {
f1dc9b30 975 close_handler *ch;
76f87348 976 fde *F = &fd_table[fd];
a3d5953d 977 debug(5, 0) ("WARNING: FD %d has handlers, but it's invalid.\n", fd);
22f5d1ca 978 debug(5, 0) ("FD %d is a %s\n", fd, fdTypeStr[fd_table[fd].type]);
a3d5953d 979 debug(5, 0) ("--> %s\n", fd_table[fd].desc);
980 debug(5, 0) ("tmout:%p read:%p write:%p\n",
76f87348 981 F->timeout_handler,
982 F->read_handler,
983 F->write_handler);
76f87348 984 for (ch = F->close_handler; ch; ch = ch->next)
a3d5953d 985 debug(5, 0) (" close handler: %p\n", ch->handler);
76f87348 986 if (F->close_handler) {
3be3bbc6 987 commCallCloseHandlers(fd);
76f87348 988 } else if (F->timeout_handler) {
a3d5953d 989 debug(5, 0) ("comm_poll: Calling Timeout Handler\n");
76f87348 990 F->timeout_handler(fd, F->timeout_data);
dcfe6390 991 }
76f87348 992 F->close_handler = NULL;
993 F->timeout_handler = NULL;
994 F->read_handler = NULL;
995 F->write_handler = NULL;
0e473d70 996 if (F->open != 0)
6cf028ab 997 fd_close(fd);
dcfe6390 998 }
97c03d3c 999 lastinc = polledinc;
dcfe6390 1000 }
1001 return COMM_OK;
97c03d3c 1002 } while (timeout > squid_curtime);
a3d5953d 1003 debug(5, 8) ("comm_poll: time out: %d.\n", squid_curtime);
dcfe6390 1004 return COMM_TIMEOUT;
055f4d4d 1005}
090089c4 1006
dcfe6390 1007#else
090089c4 1008
1009/* Select on all sockets; call handlers for those that are ready. */
b8d8561b 1010int
1011comm_select(time_t sec)
090089c4 1012{
090089c4 1013 fd_set readfds;
1014 fd_set writefds;
582b6456 1015 PF *hdl = NULL;
7d49daab 1016 int fd;
1017 int i;
1018 int maxfd;
1019 int nfds;
090089c4 1020 int num;
97c03d3c 1021 static int incoming_counter = 0;
090089c4 1022 static time_t last_timeout = 0;
1023 struct timeval poll_time;
97c03d3c 1024 static int lastinc;
7d49daab 1025 time_t timeout;
090089c4 1026
1027 /* assume all process are very fast (less than 1 second). Call
1028 * time() only once */
090089c4 1029 /* use only 1 second granularity */
b8de7ebe 1030 timeout = squid_curtime + sec;
090089c4 1031
f7361640 1032 do {
b984c445 1033#if !ALARM_UPDATES_TIME
1034 getCurrentTime();
1035#endif
6cf028ab 1036
1037#if USE_ASYNC_IO
1038 aioCheckCallbacks();
1039#endif
1040
090089c4 1041 FD_ZERO(&readfds);
1042 FD_ZERO(&writefds);
bbdb774b 1043 if (shutdown_pending || reconfigure_pending) {
30a4f2a8 1044 serverConnectionsClose();
f88bb09c 1045 dnsShutdownServers();
d2af9477 1046 redirectShutdownServers();
429fdbec 1047 /* shutdown_pending will be set to
1048 * +1 for SIGTERM
1049 * -1 for SIGINT */
bbdb774b 1050 /* reconfigure_pending always == 1 when SIGHUP received */
1051 if (shutdown_pending > 0 || reconfigure_pending > 0)
5c5783a2 1052 setSocketShutdownLifetimes(Config.shutdownLifetime);
f3753518 1053 else
3ed6e11e 1054 setSocketShutdownLifetimes(1);
30a4f2a8 1055 }
7a974f67 1056 comm_select_incoming();
4d64d74a 1057 nfds = 0;
429fdbec 1058 maxfd = Biggest_FD + 1;
4d64d74a 1059 for (i = 0; i < maxfd; i++) {
090089c4 1060 /* Check each open socket for a handler. */
da2b3a17 1061 if (fd_table[i].read_handler && !commDeferRead(i)) {
4d64d74a 1062 nfds++;
090089c4 1063 FD_SET(i, &readfds);
4d64d74a 1064 }
1065 if (fd_table[i].write_handler) {
1066 nfds++;
090089c4 1067 FD_SET(i, &writefds);
4d64d74a 1068 }
090089c4 1069 }
bbdb774b 1070 if (shutdown_pending || reconfigure_pending)
a3d5953d 1071 debug(5, 2) ("comm_select: Still waiting on %d FDs\n", nfds);
4d64d74a 1072 if (nfds == 0)
1073 return COMM_SHUTDOWN;
7690e8eb 1074 for (;;) {
89fb2544 1075 poll_time.tv_sec = sec > 0 ? 1 : 0;
090089c4 1076 poll_time.tv_usec = 0;
d0217c9b 1077 num = select(maxfd, &readfds, &writefds, NULL, &poll_time);
f2908497 1078 Counter.select_loops++;
090089c4 1079 if (num >= 0)
1080 break;
4d64d74a 1081 if (errno == EINTR)
1082 break;
a3d5953d 1083 debug(50, 0) ("comm_select: select failure: %s\n",
30a4f2a8 1084 xstrerror());
d0217c9b 1085 examine_select(&readfds, &writefds);
bf9f8f2b 1086 return COMM_ERROR;
30a4f2a8 1087 /* NOTREACHED */
090089c4 1088 }
4d64d74a 1089 if (num < 0)
1090 continue;
a3d5953d 1091 debug(5, num ? 5 : 8) ("comm_select: %d sockets ready at %d\n",
30a4f2a8 1092 num, (int) squid_curtime);
090089c4 1093
1094 /* Check lifetime and timeout handlers ONCE each second.
1095 * Replaces brain-dead check every time through the loop! */
b8de7ebe 1096 if (squid_curtime > last_timeout) {
1097 last_timeout = squid_curtime;
090089c4 1098 checkTimeouts();
090089c4 1099 }
7d49daab 1100 if (num == 0)
1101 continue;
1102
090089c4 1103 /* scan each socket but the accept socket. Poll this
2c5294ce 1104 * more frequently to minimize losses due to the 5 connect
090089c4 1105 * limit in SunOS */
1106
5742d7c9 1107 for (fd = 0; fd < maxfd; fd++) {
d0217c9b 1108 if (!FD_ISSET(fd, &readfds) && !FD_ISSET(fd, &writefds))
7d49daab 1109 continue;
7a974f67 1110 if (fdIsHttpOrIcp(fd))
7d49daab 1111 continue;
7d49daab 1112 if (FD_ISSET(fd, &readfds)) {
a3d5953d 1113 debug(5, 6) ("comm_select: FD %d ready for reading\n", fd);
7d49daab 1114 if (fd_table[fd].read_handler) {
ff8d0ea6 1115 hdl = fd_table[fd].read_handler;
76f87348 1116 fd_table[fd].read_handler = NULL;
ff8d0ea6 1117 hdl(fd, fd_table[fd].read_data);
090089c4 1118 }
7a974f67 1119 if ((++incoming_counter & 15) == 0)
1120 comm_select_incoming();
7d49daab 1121 }
1122 if (FD_ISSET(fd, &writefds)) {
a3d5953d 1123 debug(5, 5) ("comm_select: FD %d ready for writing\n", fd);
7d49daab 1124 if (fd_table[fd].write_handler) {
ff8d0ea6 1125 hdl = fd_table[fd].write_handler;
76f87348 1126 fd_table[fd].write_handler = NULL;
ff8d0ea6 1127 hdl(fd, fd_table[fd].write_data);
090089c4 1128 }
7a974f67 1129 if ((++incoming_counter & 15) == 0)
1130 comm_select_incoming();
7d49daab 1131 }
97c03d3c 1132 lastinc = polledinc;
090089c4 1133 }
7d49daab 1134 return COMM_OK;
97c03d3c 1135 } while (timeout > squid_curtime);
a3d5953d 1136 debug(5, 8) ("comm_select: time out: %d.\n", squid_curtime);
090089c4 1137 return COMM_TIMEOUT;
1138}
dcfe6390 1139#endif
090089c4 1140
b8d8561b 1141void
582b6456 1142commSetSelect(int fd, unsigned int type, PF * handler, void *client_data, time_t timeout)
090089c4 1143{
89de058c 1144 fde *F = &fd_table[fd];
489b22c1 1145 assert(fd >= 0);
89de058c 1146 assert(F->open == FD_OPEN);
cebe3f19 1147 debug(5, 5) ("commSetSelect: FD %d type %d\n", fd, type);
090089c4 1148 if (type & COMM_SELECT_READ) {
76f87348 1149 F->read_handler = handler;
1150 F->read_data = client_data;
090089c4 1151 }
1152 if (type & COMM_SELECT_WRITE) {
76f87348 1153 F->write_handler = handler;
1154 F->write_data = client_data;
090089c4 1155 }
5c5783a2 1156 if (timeout)
76f87348 1157 F->timeout = squid_curtime + timeout;
090089c4 1158}
1159
b8d8561b 1160void
582b6456 1161comm_add_close_handler(int fd, PF * handler, void *data)
30a4f2a8 1162{
f1dc9b30 1163 close_handler *new = xmalloc(sizeof(*new));
a3d5953d 1164 debug(5, 5) ("comm_add_close_handler: FD %d, handler=%p, data=%p\n",
e0c42e90 1165 fd, handler, data);
30a4f2a8 1166 new->handler = handler;
1167 new->data = data;
1168 new->next = fd_table[fd].close_handler;
1169 fd_table[fd].close_handler = new;
603a02fd 1170 cbdataLock(data);
30a4f2a8 1171}
1172
b8d8561b 1173void
582b6456 1174comm_remove_close_handler(int fd, PF * handler, void *data)
090089c4 1175{
f1dc9b30 1176 close_handler *p;
1177 close_handler *last = NULL;
30a4f2a8 1178 /* Find handler in list */
e869f2bd 1179 debug(5, 5) ("comm_remove_close_handler: FD %d, handler=%p, data=%p\n",
1180 fd, handler, data);
30a4f2a8 1181 for (p = fd_table[fd].close_handler; p != NULL; last = p, p = p->next)
1182 if (p->handler == handler && p->data == data)
1183 break; /* This is our handler */
f88211e8 1184 assert(p != NULL);
30a4f2a8 1185 /* Remove list entry */
1186 if (last)
1187 last->next = p->next;
1188 else
1189 fd_table[fd].close_handler = p->next;
1390960a 1190 cbdataUnlock(p->data);
30a4f2a8 1191 safe_free(p);
1192}
090089c4 1193
b8d8561b 1194static void
1195commSetNoLinger(int fd)
30a4f2a8 1196{
1197 struct linger L;
090089c4 1198 L.l_onoff = 0; /* off */
1199 L.l_linger = 0;
30a4f2a8 1200 if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &L, sizeof(L)) < 0)
a3d5953d 1201 debug(50, 0) ("commSetNoLinger: FD %d: %s\n", fd, xstrerror());
090089c4 1202}
1203
b8d8561b 1204static void
1205commSetReuseAddr(int fd)
090089c4 1206{
1207 int on = 1;
30a4f2a8 1208 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0)
a3d5953d 1209 debug(50, 1) ("commSetReuseAddr: FD %d: %s\n", fd, xstrerror());
090089c4 1210}
1211
b8d8561b 1212static void
1213commSetTcpRcvbuf(int fd, int size)
f868539a 1214{
1215 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *) &size, sizeof(size)) < 0)
a3d5953d 1216 debug(50, 1) ("commSetTcpRcvbuf: FD %d, SIZE %d: %s\n",
b6f794d6 1217 fd, size, xstrerror());
f868539a 1218}
1219
b8d8561b 1220int
1221commSetNonBlocking(int fd)
30a4f2a8 1222{
731e4d49 1223 int flags;
9e205701 1224 int dummy = 0;
95cf2361 1225 if ((flags = fcntl(fd, F_GETFL, dummy)) < 0) {
a3d5953d 1226 debug(50, 0) ("FD %d: fcntl F_GETFL: %s\n", fd, xstrerror());
731e4d49 1227 return COMM_ERROR;
1228 }
4f92c80c 1229 if (fcntl(fd, F_SETFL, flags | SQUID_NONBLOCK) < 0) {
a3d5953d 1230 debug(50, 0) ("commSetNonBlocking: FD %d: %s\n", fd, xstrerror());
30a4f2a8 1231 return COMM_ERROR;
090089c4 1232 }
090089c4 1233 return 0;
1234}
1235
b8d8561b 1236void
1237commSetCloseOnExec(int fd)
3ca60c86 1238{
1239#ifdef FD_CLOEXEC
731e4d49 1240 int flags;
7a18b487 1241 int dummy = 0;
c7989865 1242 if ((flags = fcntl(fd, F_GETFL, dummy)) < 0) {
a3d5953d 1243 debug(50, 0) ("FD %d: fcntl F_GETFL: %s\n", fd, xstrerror());
24382924 1244 return;
3ca60c86 1245 }
24382924 1246 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
a3d5953d 1247 debug(50, 0) ("FD %d: set close-on-exec failed: %s\n", fd, xstrerror());
3ca60c86 1248#endif
1249}
1250
e90100aa 1251#ifdef TCP_NODELAY
1252static void
1253commSetTcpNoDelay(int fd)
1254{
1255 int on = 1;
1256 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on)) < 0)
a3d5953d 1257 debug(50, 1) ("commSetTcpNoDelay: FD %d: %s\n", fd, xstrerror());
e90100aa 1258}
1259#endif
1260
b8d8561b 1261int
0673c0ba 1262comm_init(void)
090089c4 1263{
f1dc9b30 1264 fd_table = xcalloc(Squid_MaxFD, sizeof(fde));
59c4d35b 1265 /* XXX account fd_table */
090089c4 1266 /* Keep a few file descriptors free so that we don't run out of FD's
1267 * after accepting a client but before it opens a socket or a file.
e83892e9 1268 * Since Squid_MaxFD can be as high as several thousand, don't waste them */
0254ee29 1269 RESERVED_FD = XMIN(100, Squid_MaxFD / 4);
055f4d4d 1270 zero_tv.tv_sec = 0;
1271 zero_tv.tv_usec = 0;
090089c4 1272 return 0;
1273}
1274
1275
f88211e8 1276#if !HAVE_POLL
090089c4 1277/*
1278 * examine_select - debug routine.
1279 *
1280 * I spend the day chasing this core dump that occurs when both the client
1281 * and the server side of a cache fetch simultaneoulsy abort the
1282 * connection. While I haven't really studied the code to figure out how
1283 * it happens, the snippet below may prevent the cache from exitting:
1284 *
1285 * Call this from where the select loop fails.
1286 */
b8d8561b 1287static int
5742d7c9 1288examine_select(fd_set * readfds, fd_set * writefds)
090089c4 1289{
1290 int fd = 0;
bbc5ea8f 1291 fd_set read_x;
1292 fd_set write_x;
090089c4 1293 int num;
1294 struct timeval tv;
f1dc9b30 1295 close_handler *ch = NULL;
76f87348 1296 fde *F = NULL;
090089c4 1297
a3d5953d 1298 debug(5, 0) ("examine_select: Examining open file descriptors...\n");
e83892e9 1299 for (fd = 0; fd < Squid_MaxFD; fd++) {
090089c4 1300 FD_ZERO(&read_x);
1301 FD_ZERO(&write_x);
090089c4 1302 tv.tv_sec = tv.tv_usec = 0;
af00901c 1303 if (FD_ISSET(fd, readfds))
090089c4 1304 FD_SET(fd, &read_x);
af00901c 1305 else if (FD_ISSET(fd, writefds))
1306 FD_SET(fd, &write_x);
af00901c 1307 else
1308 continue;
e83892e9 1309 num = select(Squid_MaxFD, &read_x, &write_x, NULL, &tv);
af00901c 1310 if (num > -1) {
a3d5953d 1311 debug(5, 5) ("FD %d is valid.\n", fd);
af00901c 1312 continue;
1313 }
76f87348 1314 F = &fd_table[fd];
a3d5953d 1315 debug(5, 0) ("FD %d: %s\n", fd, xstrerror());
1316 debug(5, 0) ("WARNING: FD %d has handlers, but it's invalid.\n", fd);
1317 debug(5, 0) ("FD %d is a %s called '%s'\n",
ca98227c 1318 fd,
22f5d1ca 1319 fdTypeStr[fd_table[fd].type],
76f87348 1320 F->desc);
a3d5953d 1321 debug(5, 0) ("tmout:%p read:%p write:%p\n",
76f87348 1322 F->timeout_handler,
1323 F->read_handler,
1324 F->write_handler);
1325 for (ch = F->close_handler; ch; ch = ch->next)
a3d5953d 1326 debug(5, 0) (" close handler: %p\n", ch->handler);
76f87348 1327 if (F->close_handler) {
3be3bbc6 1328 commCallCloseHandlers(fd);
76f87348 1329 } else if (F->timeout_handler) {
a3d5953d 1330 debug(5, 0) ("examine_select: Calling Timeout Handler\n");
76f87348 1331 F->timeout_handler(fd, F->timeout_data);
090089c4 1332 }
76f87348 1333 F->close_handler = NULL;
1334 F->timeout_handler = NULL;
1335 F->read_handler = NULL;
1336 F->write_handler = NULL;
af00901c 1337 FD_CLR(fd, readfds);
1338 FD_CLR(fd, writefds);
090089c4 1339 }
090089c4 1340 return 0;
1341}
dcfe6390 1342#endif
090089c4 1343
b8d8561b 1344static void
0673c0ba 1345checkTimeouts(void)
090089c4 1346{
1347 int fd;
76f87348 1348 fde *F = NULL;
5c5783a2 1349 PF *callback;
429fdbec 1350 for (fd = 0; fd <= Biggest_FD; fd++) {
76f87348 1351 F = &fd_table[fd];
1352 if (F->open != FD_OPEN)
429fdbec 1353 continue;
76f87348 1354 if (F->timeout == 0)
30a4f2a8 1355 continue;
76f87348 1356 if (F->timeout > squid_curtime)
30a4f2a8 1357 continue;
a3d5953d 1358 debug(5, 5) ("checkTimeouts: FD %d Expired\n", fd);
76f87348 1359 if (F->timeout_handler) {
a3d5953d 1360 debug(5, 5) ("checkTimeouts: FD %d: Call timeout handler\n", fd);
76f87348 1361 callback = F->timeout_handler;
1362 F->timeout_handler = NULL;
1363 callback(fd, F->timeout_data);
30a4f2a8 1364 } else {
a3d5953d 1365 debug(5, 5) ("checkTimeouts: FD %d: Forcing comm_close()\n", fd);
30a4f2a8 1366 comm_close(fd);
090089c4 1367 }
1368 }
1369}
1370
30a4f2a8 1371/* Write to FD. */
b8d8561b 1372static void
582b6456 1373commHandleWrite(int fd, void *data)
30a4f2a8 1374{
f17936ab 1375 CommWriteStateData *state = data;
30a4f2a8 1376 int len = 0;
1377 int nleft;
1378
cebe3f19 1379 debug(5, 5) ("commHandleWrite: FD %d: off %d, sz %d.\n",
1380 fd, state->offset, state->size);
30a4f2a8 1381
1382 nleft = state->size - state->offset;
1383 len = write(fd, state->buf + state->offset, nleft);
b69f7771 1384 fd_bytes(fd, len, FD_WRITE);
30a4f2a8 1385
1386 if (len == 0) {
1387 /* Note we even call write if nleft == 0 */
1388 /* We're done */
1389 if (nleft != 0)
02be0294 1390 debug(5, 1) ("commHandleWrite: FD %d: write failure: connection closed with %d bytes remaining.\n", fd, nleft);
f17936ab 1391 CommWriteStateCallbackAndFree(fd, nleft ? COMM_ERROR : COMM_OK);
30a4f2a8 1392 } else if (len < 0) {
1393 /* An error */
26a880e2 1394 if (ignoreErrno(errno)) {
a3d5953d 1395 debug(50, 10) ("commHandleWrite: FD %d: write failure: %s.\n",
30a4f2a8 1396 fd, xstrerror());
b177367b 1397 commSetSelect(fd,
30a4f2a8 1398 COMM_SELECT_WRITE,
cd1fb0eb 1399 commHandleWrite,
b177367b 1400 state,
85d7ea98 1401 0);
9864ee44 1402 } else {
a3d5953d 1403 debug(50, 2) ("commHandleWrite: FD %d: write failure: %s.\n",
9864ee44 1404 fd, xstrerror());
f17936ab 1405 CommWriteStateCallbackAndFree(fd, COMM_ERROR);
30a4f2a8 1406 }
30a4f2a8 1407 } else {
1408 /* A successful write, continue */
1409 state->offset += len;
1410 if (state->offset < state->size) {
1411 /* Not done, reinstall the write handler and write some more */
b177367b 1412 commSetSelect(fd,
30a4f2a8 1413 COMM_SELECT_WRITE,
cd1fb0eb 1414 commHandleWrite,
b177367b 1415 state,
85d7ea98 1416 0);
9864ee44 1417 } else {
f17936ab 1418 CommWriteStateCallbackAndFree(fd, COMM_OK);
30a4f2a8 1419 }
30a4f2a8 1420 }
1421}
1422
1423
1424
1425/* Select for Writing on FD, until SIZE bytes are sent. Call
1426 * * HANDLER when complete. */
b8d8561b 1427void
9e4ad609 1428comm_write(int fd, char *buf, int size, CWCB * handler, void *handler_data, FREE * free_func)
30a4f2a8 1429{
aa9e2cab 1430 CommWriteStateData *state = fd_table[fd].rwstate;
a3d5953d 1431 debug(5, 5) ("comm_write: FD %d: sz %d: hndl %p: data %p.\n",
787869c5 1432 fd, size, handler, handler_data);
aa9e2cab 1433 if (NULL != state) {
0e473d70 1434 debug(5, 1) ("comm_write: fd_table[%d].rwstate != NULL", fd);
aa9e2cab 1435 safe_free(state);
6cf028ab 1436 fd_table[fd].rwstate = NULL;
1437 }
aa9e2cab 1438 assert(state == NULL);
1439 fd_table[fd].rwstate = state = xcalloc(1, sizeof(CommWriteStateData));
30a4f2a8 1440 state->buf = buf;
1441 state->size = size;
1442 state->offset = 0;
1443 state->handler = handler;
30a4f2a8 1444 state->handler_data = handler_data;
c0dec081 1445 state->free_func = free_func;
1a8f5ed6 1446 cbdataLock(handler_data);
aa9e2cab 1447 commSetSelect(fd, COMM_SELECT_WRITE, commHandleWrite, state, 0);
30a4f2a8 1448}
26a880e2 1449
cb69b4c7 1450/* a wrapper around comm_write to allow for MemBuf to comm_written in a snap */
1451void
1452comm_write_mbuf(int fd, MemBuf mb, CWCB * handler, void *handler_data)
1453{
1454 comm_write(fd, mb.buf, mb.size, handler, handler_data, memBufFreeFunc(&mb));
1455}
1456
b224ea98 1457int
edd2eb63 1458ignoreErrno(int ierrno)
26a880e2 1459{
edd2eb63 1460 if (ierrno == EWOULDBLOCK)
26a880e2 1461 return 1;
1462#if EAGAIN != EWOULDBLOCK
edd2eb63 1463 if (ierrno == EAGAIN)
26a880e2 1464 return 1;
1465#endif
edd2eb63 1466 if (ierrno == EALREADY)
26a880e2 1467 return 1;
edd2eb63 1468 if (ierrno == EINTR)
26a880e2 1469 return 1;
1470 return 0;
1471}
22c653cd 1472
1473static void
1474commSetConnectTimeout(int fd, time_t timeout)
1475{
1476 fde *F = &fd_table[fd];
1477 F->connect_timeout = timeout;
1478}