]> git.ipfire.org Git - thirdparty/squid.git/blame - src/comm.cc
- Removed 'was assert' commengs
[thirdparty/squid.git] / src / comm.cc
CommitLineData
da2b3a17 1
30a4f2a8 2/*
96f1be5d 3 * $Id: comm.cc,v 1.196 1997/10/26 02:33:17 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
114/* Block processing new client requests (accepts on ascii port) when we start
115 * running shy of free file descriptors. For example, under SunOS, we'll keep
116 * 64 file descriptors free for disk-i/o and connections to remote servers */
117
090089c4 118#define min(x,y) ((x)<(y)? (x) : (y))
119#define max(a,b) ((a)>(b)? (a) : (b))
120
f88211e8 121typedef struct {
122 char *host;
123 u_short port;
124 struct sockaddr_in S;
125 CNCB *callback;
126 void *data;
127 int tries;
128 struct in_addr in_addr;
129 int locks;
03a1ee42 130 int fd;
f88211e8 131} ConnectStateData;
132
090089c4 133/* STATIC */
0b2db32c 134static int polledinc = 0;
f5b8bbc4 135static int commBind(int s, struct in_addr, u_short port);
f88211e8 136#if !HAVE_POLL
f5b8bbc4 137static int examine_select(fd_set *, fd_set *);
dcfe6390 138#endif
f5b8bbc4 139static void checkTimeouts(void);
140static void commSetReuseAddr(int);
141static void commSetNoLinger(int);
812ed90c 142#if HAVE_POLL
f5b8bbc4 143static void comm_poll_incoming(void);
812ed90c 144#else
f5b8bbc4 145static void comm_select_incoming(void);
812ed90c 146#endif
f5b8bbc4 147static void CommWriteStateCallbackAndFree(int fd, int code);
30a4f2a8 148#ifdef TCP_NODELAY
f5b8bbc4 149static void commSetTcpNoDelay(int);
30a4f2a8 150#endif
f5b8bbc4 151static void commSetTcpRcvbuf(int, int);
f88211e8 152static PF commConnectFree;
03a1ee42 153static PF commConnectHandle;
154static PF commHandleWrite;
f5b8bbc4 155static int fdIsHttpOrIcp(int fd);
edeb28fd 156static IPH commConnectDnsHandle;
f5b8bbc4 157static void commConnectCallback(ConnectStateData * cs, int status);
da2b3a17 158static int commDeferRead(int fd);
26a880e2 159static int ignoreErrno(int errno);
30a4f2a8 160
30a4f2a8 161static struct timeval zero_tv;
090089c4 162
b8d8561b 163static void
f17936ab 164CommWriteStateCallbackAndFree(int fd, int code)
9864ee44 165{
f17936ab 166 CommWriteStateData *CommWriteState = fd_table[fd].rwstate;
167 CWCB *callback = NULL;
1a8f5ed6 168 void *data;
a56a3abe 169 fd_table[fd].rwstate = NULL;
f17936ab 170 if (CommWriteState == NULL)
9864ee44 171 return;
f17936ab 172 if (CommWriteState->free) {
173 CommWriteState->free(CommWriteState->buf);
174 CommWriteState->buf = NULL;
9864ee44 175 }
f17936ab 176 callback = CommWriteState->handler;
1a8f5ed6 177 data = CommWriteState->handler_data;
f17936ab 178 CommWriteState->handler = NULL;
1a8f5ed6 179 if (callback && cbdataValid(data))
180 callback(fd, CommWriteState->buf, CommWriteState->offset, code, data);
181 cbdataUnlock(data);
f17936ab 182 safe_free(CommWriteState);
9864ee44 183}
184
090089c4 185/* Return the local port associated with fd. */
b8d8561b 186u_short
187comm_local_port(int fd)
090089c4 188{
189 struct sockaddr_in addr;
190 int addr_len = 0;
76f87348 191 fde *F = &fd_table[fd];
090089c4 192
090089c4 193 /* If the fd is closed already, just return */
76f87348 194 if (!F->open) {
a3d5953d 195 debug(5, 0) ("comm_local_port: FD %d has been closed.\n", fd);
30a4f2a8 196 return 0;
090089c4 197 }
76f87348 198 if (F->local_port)
199 return F->local_port;
090089c4 200 addr_len = sizeof(addr);
201 if (getsockname(fd, (struct sockaddr *) &addr, &addr_len)) {
a3d5953d 202 debug(50, 1) ("comm_local_port: Failed to retrieve TCP/UDP port number for socket: FD %d: %s\n", fd, xstrerror());
30a4f2a8 203 return 0;
090089c4 204 }
a3d5953d 205 debug(5, 6) ("comm_local_port: FD %d: sockaddr %u.\n", fd, addr.sin_addr.s_addr);
76f87348 206 F->local_port = ntohs(addr.sin_port);
207 return F->local_port;
090089c4 208}
209
b8d8561b 210static int
211commBind(int s, struct in_addr in_addr, u_short port)
090089c4 212{
213 struct sockaddr_in S;
090089c4 214
090089c4 215 memset(&S, '\0', sizeof(S));
216 S.sin_family = AF_INET;
217 S.sin_port = htons(port);
30a4f2a8 218 S.sin_addr = in_addr;
090089c4 219 if (bind(s, (struct sockaddr *) &S, sizeof(S)) == 0)
220 return COMM_OK;
a3d5953d 221 debug(50, 0) ("commBind: Cannot bind socket FD %d to %s:%d: %s\n",
090089c4 222 s,
30a4f2a8 223 S.sin_addr.s_addr == INADDR_ANY ? "*" : inet_ntoa(S.sin_addr),
44a62238 224 (int) port,
225 xstrerror());
090089c4 226 return COMM_ERROR;
227}
228
229/* Create a socket. Default is blocking, stream (TCP) socket. IO_TYPE
230 * is OR of flags specified in comm.h. */
b8d8561b 231int
16b204c4 232comm_open(int sock_type,
cc6a9d2e 233 int proto,
234 struct in_addr addr,
235 u_short port,
236 int flags,
0ee4272b 237 const char *note)
090089c4 238{
239 int new_socket;
76f87348 240 fde *F = NULL;
b6f794d6 241 int tcp_rcv_bufsz = Config.tcpRcvBufsz;
090089c4 242
243 /* Create socket for accepting new connections. */
16b204c4 244 if ((new_socket = socket(AF_INET, sock_type, proto)) < 0) {
090089c4 245 /* Increase the number of reserved fd's if calls to socket()
246 * are failing because the open file table is full. This
247 * limits the number of simultaneous clients */
248 switch (errno) {
249 case ENFILE:
250 case EMFILE:
a3d5953d 251 debug(50, 1) ("comm_open: socket failure: %s\n", xstrerror());
090089c4 252 break;
253 default:
a3d5953d 254 debug(50, 0) ("comm_open: socket failure: %s\n", xstrerror());
090089c4 255 }
603a02fd 256 return -1;
090089c4 257 }
258 /* update fdstat */
365e5b34 259 debug(5, 5) ("comm_open: FD %d is a new socket\n", new_socket);
5c5783a2 260 fd_open(new_socket, FD_SOCKET, note);
76f87348 261 F = &fd_table[new_socket];
16b204c4 262 if (!BIT_TEST(flags, COMM_NOCLOEXEC))
3ca60c86 263 commSetCloseOnExec(new_socket);
7690e8eb 264 if (port > (u_short) 0) {
30a4f2a8 265 commSetNoLinger(new_socket);
266 if (do_reuse)
090089c4 267 commSetReuseAddr(new_socket);
090089c4 268 }
a3724d50 269 if (addr.s_addr != no_addr.s_addr) {
270 if (commBind(new_socket, addr, port) != COMM_OK) {
271 comm_close(new_socket);
603a02fd 272 return -1;
a3724d50 273 }
23ff6968 274 }
76f87348 275 F->local_port = port;
090089c4 276
16b204c4 277 if (BIT_TEST(flags, COMM_NONBLOCKING))
30a4f2a8 278 if (commSetNonBlocking(new_socket) == COMM_ERROR)
603a02fd 279 return -1;
30a4f2a8 280#ifdef TCP_NODELAY
281 if (sock_type == SOCK_STREAM)
282 commSetTcpNoDelay(new_socket);
283#endif
f868539a 284 if (tcp_rcv_bufsz > 0 && sock_type == SOCK_STREAM)
285 commSetTcpRcvbuf(new_socket, tcp_rcv_bufsz);
090089c4 286 return new_socket;
287}
288
289 /*
e83892e9 290 * NOTE: set the listen queue to Squid_MaxFD/4 and rely on the kernel to
090089c4 291 * impose an upper limit. Solaris' listen(3n) page says it has
292 * no limit on this parameter, but sys/socket.h sets SOMAXCONN
293 * to 5. HP-UX currently has a limit of 20. SunOS is 5 and
294 * OSF 3.0 is 8.
295 */
b8d8561b 296int
297comm_listen(int sock)
090089c4 298{
299 int x;
e83892e9 300 if ((x = listen(sock, Squid_MaxFD >> 2)) < 0) {
a3d5953d 301 debug(50, 0) ("comm_listen: listen(%d, %d): %s\n",
e83892e9 302 Squid_MaxFD >> 2,
090089c4 303 sock, xstrerror());
304 return x;
305 }
306 return sock;
307}
308
e5f6c5c2 309void
4f92c80c 310commConnectStart(int fd, const char *host, u_short port, CNCB * callback, void *data)
e924600d 311{
312 ConnectStateData *cs = xcalloc(1, sizeof(ConnectStateData));
8407afee 313 cbdataAdd(cs);
03a1ee42 314 cs->fd = fd;
e924600d 315 cs->host = xstrdup(host);
316 cs->port = port;
317 cs->callback = callback;
318 cs->data = data;
b716a8ad 319 cbdataLock(cs->data);
e924600d 320 comm_add_close_handler(fd, commConnectFree, cs);
f88211e8 321 cs->locks++;
8407afee 322 ipcache_nbgethostbyname(host, commConnectDnsHandle, cs);
edeb28fd 323}
324
325static void
03a1ee42 326commConnectDnsHandle(const ipcache_addrs * ia, void *data)
edeb28fd 327{
328 ConnectStateData *cs = data;
f88211e8 329 assert(cs->locks == 1);
330 cs->locks--;
edeb28fd 331 if (ia == NULL) {
a3d5953d 332 debug(5, 3) ("commConnectDnsHandle: Unknown host: %s\n", cs->host);
03a1ee42 333 commConnectCallback(cs, COMM_ERR_DNS);
edeb28fd 334 return;
335 }
f076b37b 336 assert(ia->cur < ia->count);
edeb28fd 337 cs->in_addr = ia->in_addrs[ia->cur];
03a1ee42 338 commConnectHandle(cs->fd, cs);
e924600d 339}
340
f88211e8 341static void
03a1ee42 342commConnectCallback(ConnectStateData * cs, int status)
f88211e8 343{
a3d5953d 344 CNCB *callback = cs->callback;
345 void *data = cs->data;
03a1ee42 346 int fd = cs->fd;
a3d5953d 347 comm_remove_close_handler(fd, commConnectFree, cs);
348 commConnectFree(fd, cs);
8407afee 349 if (cbdataValid(data))
365e5b34 350 callback(fd, status, data);
b716a8ad 351 cbdataUnlock(cs->data);
f88211e8 352}
353
e924600d 354static void
03a1ee42 355commConnectFree(int fdunused, void *data)
e924600d 356{
357 ConnectStateData *cs = data;
8407afee 358 if (cs->locks)
365e5b34 359 ipcacheUnregister(cs->host, cs);
8407afee 360 safe_free(cs->host);
361 cbdataFree(cs);
e924600d 362}
363
edeb28fd 364static int
f88211e8 365commRetryConnect(int fd, ConnectStateData * cs)
edeb28fd 366{
367 int fd2;
f88211e8 368 if (++cs->tries == 4)
edeb28fd 369 return 0;
7dd44885 370 if (!cbdataValid(cs->data))
371 return 0;
edeb28fd 372 fd2 = socket(AF_INET, SOCK_STREAM, 0);
373 if (fd2 < 0) {
a3d5953d 374 debug(5, 0) ("commRetryConnect: socket: %s\n", xstrerror());
edeb28fd 375 return 0;
376 }
377 if (dup2(fd2, fd) < 0) {
a3d5953d 378 debug(5, 0) ("commRetryConnect: dup2: %s\n", xstrerror());
edeb28fd 379 return 0;
380 }
381 commSetNonBlocking(fd);
382 close(fd2);
383 return 1;
384}
385
e924600d 386/* Connect SOCK to specified DEST_PORT at DEST_HOST. */
387static void
388commConnectHandle(int fd, void *data)
090089c4 389{
f88211e8 390 ConnectStateData *cs = data;
391 if (cs->S.sin_addr.s_addr == 0) {
392 cs->S.sin_family = AF_INET;
393 cs->S.sin_addr = cs->in_addr;
394 cs->S.sin_port = htons(cs->port);
17a0a4ee 395 if (Config.onoff.log_fqdn)
f88211e8 396 fqdncache_gethostbyaddr(cs->S.sin_addr, FQDN_LOOKUP_IF_MISS);
e5f6c5c2 397 }
f88211e8 398 switch (comm_connect_addr(fd, &cs->S)) {
e5f6c5c2 399 case COMM_INPROGRESS:
489b22c1 400 debug(5, 5) ("FD %d: COMM_INPROGRESS\n", fd);
f88211e8 401 commSetSelect(fd, COMM_SELECT_WRITE, commConnectHandle, cs, 0);
e5f6c5c2 402 break;
403 case COMM_OK:
f88211e8 404 ipcacheCycleAddr(cs->host);
03a1ee42 405 commConnectCallback(cs, COMM_OK);
e5f6c5c2 406 break;
407 default:
f88211e8 408 if (commRetryConnect(fd, cs)) {
0b6647bb 409 debug(5, 2) ("Retrying connection to %s: %s\n",
f88211e8 410 cs->host, xstrerror());
411 cs->S.sin_addr.s_addr = 0;
412 ipcacheCycleAddr(cs->host);
413 cs->locks++;
8407afee 414 ipcache_nbgethostbyname(cs->host, commConnectDnsHandle, cs);
edeb28fd 415 } else {
f88211e8 416 ipcacheRemoveBadAddr(cs->host, cs->S.sin_addr);
03a1ee42 417 commConnectCallback(cs, COMM_ERR_CONNECT);
edeb28fd 418 }
e5f6c5c2 419 break;
090089c4 420 }
090089c4 421}
b8d8561b 422int
4f92c80c 423commSetTimeout(int fd, int timeout, PF * handler, void *data)
090089c4 424{
76f87348 425 fde *F;
a3d5953d 426 debug(5, 3) ("commSetTimeout: FD %d timeout %d\n", fd, timeout);
03eb2f01 427 assert(fd >= 0);
428 assert(fd < Squid_MaxFD);
76f87348 429 F = &fd_table[fd];
5c5783a2 430 if (timeout < 0) {
76f87348 431 F->timeout_handler = NULL;
432 F->timeout_data = NULL;
433 return F->timeout = 0;
5c5783a2 434 }
bbdb774b 435 if (shutdown_pending || reconfigure_pending) {
4f92c80c 436 /* don't increase the timeout if something pending */
76f87348 437 if (F->timeout > 0 && (int) (F->timeout - squid_curtime) < timeout)
438 return F->timeout;
5c5783a2 439 }
76f87348 440 assert(handler || F->timeout_handler);
5c5783a2 441 if (handler || data) {
76f87348 442 F->timeout_handler = handler;
443 F->timeout_data = data;
30a4f2a8 444 }
76f87348 445 return F->timeout = squid_curtime + (time_t) timeout;
090089c4 446}
447
b8d8561b 448int
0ee4272b 449comm_connect_addr(int sock, const struct sockaddr_in *address)
090089c4 450{
451 int status = COMM_OK;
76f87348 452 fde *F = &fd_table[sock];
090089c4 453 int len;
454 int x;
489b22c1 455 assert(ntohs(address->sin_port) != 0);
090089c4 456 /* Establish connection. */
086bce16 457 if (connect(sock, (struct sockaddr *) address, sizeof(struct sockaddr_in)) < 0) {
365e5b34 458 debug(5, 9) ("connect FD %d: %s\n", sock, xstrerror());
090089c4 459 switch (errno) {
460 case EALREADY:
30a4f2a8 461#if EAGAIN != EWOULDBLOCK
462 case EAGAIN:
463#endif
0a0bf5db 464 case EINTR:
30a4f2a8 465 case EWOULDBLOCK:
090089c4 466 case EINPROGRESS:
e5f6c5c2 467 status = COMM_INPROGRESS;
090089c4 468 break;
469 case EISCONN:
470 status = COMM_OK;
471 break;
472 case EINVAL:
473 len = sizeof(x);
474 if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *) &x, &len) >= 0)
475 errno = x;
476 default:
a3d5953d 477 debug(50, 2) ("connect: %s:%d: %s.\n",
28ab0c0a 478 fqdnFromAddr(address->sin_addr),
090089c4 479 ntohs(address->sin_port),
480 xstrerror());
481 return COMM_ERROR;
482 }
e5f6c5c2 483 }
76f87348 484 xstrncpy(F->ipaddr, inet_ntoa(address->sin_addr), 16);
485 F->remote_port = ntohs(address->sin_port);
090089c4 486 if (status == COMM_OK) {
a3d5953d 487 debug(5, 10) ("comm_connect_addr: FD %d connected to %s:%d\n",
76f87348 488 sock, F->ipaddr, F->remote_port);
f21cd581 489 } else if (status == COMM_INPROGRESS) {
a3d5953d 490 debug(5, 10) ("comm_connect_addr: FD %d connection pending\n", sock);
090089c4 491 }
492 /* Add new socket to list of open sockets. */
090089c4 493 return status;
494}
495
496/* Wait for an incoming connection on FD. FD should be a socket returned
497 * from comm_listen. */
b8d8561b 498int
499comm_accept(int fd, struct sockaddr_in *peer, struct sockaddr_in *me)
090089c4 500{
501 int sock;
1f9afe33 502 struct sockaddr_in P;
503 struct sockaddr_in M;
090089c4 504 int Slen;
76f87348 505 fde *F = NULL;
090089c4 506
1f9afe33 507 Slen = sizeof(P);
508 while ((sock = accept(fd, (struct sockaddr *) &P, &Slen)) < 0) {
090089c4 509 switch (errno) {
510#if EAGAIN != EWOULDBLOCK
511 case EAGAIN:
512#endif
513 case EWOULDBLOCK:
090089c4 514 case EINTR:
0a0bf5db 515 return COMM_NOMESSAGE;
090089c4 516 case ENFILE:
517 case EMFILE:
090089c4 518 return COMM_ERROR;
519 default:
a3d5953d 520 debug(50, 1) ("comm_accept: FD %d: accept failure: %s\n",
090089c4 521 fd, xstrerror());
522 return COMM_ERROR;
523 }
524 }
525
526 if (peer)
1f9afe33 527 *peer = P;
4053a845 528 Slen = sizeof(M);
529 memset(&M, '\0', Slen);
530 getsockname(sock, (struct sockaddr *) &M, &Slen);
531 if (me)
1f9afe33 532 *me = M;
3ca60c86 533 commSetCloseOnExec(sock);
090089c4 534 /* fdstat update */
5c5783a2 535 fd_open(sock, FD_SOCKET, "HTTP Request");
76f87348 536 F = &fd_table[sock];
537 strcpy(F->ipaddr, inet_ntoa(P.sin_addr));
538 F->remote_port = htons(P.sin_port);
539 F->local_port = htons(M.sin_port);
090089c4 540 commSetNonBlocking(sock);
090089c4 541 return sock;
542}
543
cb201b7e 544void
545commCallCloseHandlers(int fd)
546{
76f87348 547 fde *F = &fd_table[fd];
f1dc9b30 548 close_handler *ch;
a3d5953d 549 debug(5, 5) ("commCallCloseHandlers: FD %d\n", fd);
76f87348 550 while ((ch = F->close_handler) != NULL) {
551 F->close_handler = ch->next;
603a02fd 552 if (cbdataValid(ch->data))
553 ch->handler(fd, ch->data);
554 cbdataUnlock(ch->data);
cb201b7e 555 safe_free(ch);
556 }
557}
558
b8d8561b 559void
560comm_close(int fd)
090089c4 561{
76f87348 562 fde *F = NULL;
a3d5953d 563 debug(5, 5) ("comm_close: FD %d\n", fd);
03eb2f01 564 assert(fd >= 0);
565 assert(fd < Squid_MaxFD);
76f87348 566 F = &fd_table[fd];
e102ebda 567 if (BIT_TEST(F->flags, FD_CLOSING))
568 return;
b716a8ad 569 assert(F->open);
76f87348 570 assert(F->type != FD_FILE);
e102ebda 571 BIT_SET(F->flags, FD_CLOSING);
96f1be5d 572 CommWriteStateCallbackAndFree(fd, COMM_ERR_CLOSING);
cb201b7e 573 commCallCloseHandlers(fd);
b716a8ad 574 if (F->uses) /* assume persistent connect count */
575 pconnHistCount(1, F->uses);
5c5783a2 576 fd_close(fd); /* update fdstat */
0a0bf5db 577#if USE_ASYNC_IO
578 aioClose(fd);
579#else
9864ee44 580 close(fd);
0a0bf5db 581#endif
090089c4 582}
583
090089c4 584
585/* Send a udp datagram to specified PORT at HOST. */
b8d8561b 586int
0ee4272b 587comm_udp_send(int fd, const char *host, u_short port, const char *buf, int len)
090089c4 588{
0ee4272b 589 const ipcache_addrs *ia = NULL;
090089c4 590 static struct sockaddr_in to_addr;
591 int bytes_sent;
592
593 /* Set up the destination socket address for message to send to. */
594 to_addr.sin_family = AF_INET;
595
e5f6c5c2 596 if ((ia = ipcache_gethostbyname(host, IP_BLOCKING_LOOKUP)) == 0) {
a3d5953d 597 debug(50, 1) ("comm_udp_send: gethostbyname failure: %s: %s\n",
090089c4 598 host, xstrerror());
599 return (COMM_ERROR);
600 }
e5f6c5c2 601 to_addr.sin_addr = ia->in_addrs[ia->cur];
090089c4 602 to_addr.sin_port = htons(port);
603 if ((bytes_sent = sendto(fd, buf, len, 0, (struct sockaddr *) &to_addr,
604 sizeof(to_addr))) < 0) {
a3d5953d 605 debug(50, 1) ("comm_udp_send: sendto failure: FD %d: %s\n",
090089c4 606 fd, xstrerror());
607 return COMM_ERROR;
608 }
609 return bytes_sent;
610}
611
612/* Send a udp datagram to specified TO_ADDR. */
b8d8561b 613int
5df61230 614comm_udp_sendto(int fd,
615 const struct sockaddr_in *to_addr,
616 int addr_len,
617 const char *buf,
618 int len)
090089c4 619{
5df61230 620 int x;
621 x = sendto(fd, buf, len, 0, (struct sockaddr *) to_addr, addr_len);
622 if (x < 0) {
a3d5953d 623 debug(50, 1) ("comm_udp_sendto: FD %d, %s, port %d: %s\n",
5df61230 624 fd,
625 inet_ntoa(to_addr->sin_addr),
626 (int) htons(to_addr->sin_port),
627 xstrerror());
090089c4 628 return COMM_ERROR;
629 }
5df61230 630 return x;
090089c4 631}
632
b8d8561b 633void
70a9dab4 634commSetDefer(int fd, DEFER * func, void *data)
4883993a 635{
da2b3a17 636 fde *F = &fd_table[fd];
637 F->defer_check = func;
70a9dab4 638 F->defer_data = data;
4883993a 639}
640
da2b3a17 641static int
642commDeferRead(int fd)
643{
644 fde *F = &fd_table[fd];
645 if (F->defer_check == NULL)
646 return 0;
70a9dab4 647 return F->defer_check(fd, F->defer_data);
da2b3a17 648}
dcfe6390 649
f88211e8 650#if HAVE_POLL
dcfe6390 651
652/* poll() version by:
653 * Stewart Forster <slf@connect.com.au>, and
654 * Anthony Baxter <arb@connect.com.au> */
655
656static void
812ed90c 657comm_poll_incoming(void)
dcfe6390 658{
429fdbec 659 int fd;
996a0a51 660 int fds[4];
0b2421ea 661 struct pollfd pfds[3 + MAXHTTPPORTS];
996a0a51 662 unsigned long N = 0;
429fdbec 663 unsigned long i, nfds;
812ed90c 664 int j;
582b6456 665 PF *hdl = NULL;
97c03d3c 666 polledinc = 0;
dcfe6390 667 if (theInIcpConnection >= 0)
668 fds[N++] = theInIcpConnection;
933c6d93 669 if (theInIcpConnection != theOutIcpConnection)
1793867a 670 if (theOutIcpConnection >= 0)
933c6d93 671 fds[N++] = theOutIcpConnection;
0b2421ea 672 for (j = 0; j < NHttpSockets; j++) {
812ed90c 673 if (HttpSockets[j] < 0)
0b2421ea 674 continue;
da2b3a17 675 if (commDeferRead(HttpSockets[j]))
0b2421ea 676 continue;
812ed90c 677 fds[N++] = HttpSockets[j];
678 }
429fdbec 679 for (i = nfds = 0; i < N; i++) {
680 int events;
dcfe6390 681 fd = fds[i];
429fdbec 682 events = 0;
683 if (fd_table[fd].read_handler)
684 events |= POLLRDNORM;
685 if (fd_table[fd].write_handler)
686 events |= POLLWRNORM;
687 if (events) {
688 pfds[nfds].fd = fd;
689 pfds[nfds].events = events;
690 pfds[nfds].revents = 0;
691 nfds++;
dcfe6390 692 }
dcfe6390 693 }
429fdbec 694 if (!nfds)
695 return;
97c03d3c 696 polledinc = poll(pfds, nfds, 0);
697 if (polledinc < 1) {
698 polledinc = 0;
996a0a51 699 return;
97c03d3c 700 }
429fdbec 701 for (i = 0; i < nfds; i++) {
702 int revents;
703 if (((revents = pfds[i].revents) == 0) || ((fd = pfds[i].fd) == -1))
dcfe6390 704 continue;
429fdbec 705 if (revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) {
706 hdl = fd_table[fd].read_handler;
76f87348 707 fd_table[fd].read_handler = NULL;
429fdbec 708 hdl(fd, fd_table[fd].read_data);
dcfe6390 709 }
429fdbec 710 if (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) {
711 hdl = fd_table[fd].write_handler;
76f87348 712 fd_table[fd].write_handler = NULL;
429fdbec 713 hdl(fd, fd_table[fd].write_data);
dcfe6390 714 }
715 }
716 /* TO FIX: repoll ICP connection here */
717}
718
ca98227c 719#else
dcfe6390 720
b8d8561b 721static void
0673c0ba 722comm_select_incoming(void)
055f4d4d 723{
724 fd_set read_mask;
725 fd_set write_mask;
726 int maxfd = 0;
727 int fd = 0;
0b2421ea 728 int fds[3 + MAXHTTPPORTS];
055f4d4d 729 int N = 0;
730 int i = 0;
582b6456 731 PF *hdl = NULL;
97c03d3c 732 polledinc = 0;
055f4d4d 733 FD_ZERO(&read_mask);
734 FD_ZERO(&write_mask);
0b2421ea 735 for (i = 0; i < NHttpSockets; i++) {
812ed90c 736 if (HttpSockets[i] < 0)
0b2421ea 737 continue;
da2b3a17 738 if (commDeferRead(HttpSockets[i]))
0b2421ea 739 continue;
812ed90c 740 fds[N++] = HttpSockets[i];
741 }
30a4f2a8 742 if (theInIcpConnection >= 0)
743 fds[N++] = theInIcpConnection;
933c6d93 744 if (theInIcpConnection != theOutIcpConnection)
745 if (theOutIcpConnection >= 0)
746 fds[N++] = theOutIcpConnection;
055f4d4d 747 fds[N++] = 0;
055f4d4d 748 for (i = 0; i < N; i++) {
749 fd = fds[i];
750 if (fd_table[fd].read_handler) {
751 FD_SET(fd, &read_mask);
752 if (fd > maxfd)
753 maxfd = fd;
754 }
755 if (fd_table[fd].write_handler) {
756 FD_SET(fd, &write_mask);
757 if (fd > maxfd)
758 maxfd = fd;
759 }
760 }
055f4d4d 761 if (maxfd++ == 0)
762 return;
97c03d3c 763 polledinc = select(maxfd, &read_mask, &write_mask, NULL, &zero_tv);
764 if (polledinc < 1) {
765 polledinc = 0;
dcfe6390 766 return;
97c03d3c 767 }
dcfe6390 768 for (i = 0; i < N; i++) {
769 fd = fds[i];
770 if (FD_ISSET(fd, &read_mask)) {
771 hdl = fd_table[fd].read_handler;
76f87348 772 fd_table[fd].read_handler = NULL;
dcfe6390 773 hdl(fd, fd_table[fd].read_data);
774 }
775 if (FD_ISSET(fd, &write_mask)) {
776 hdl = fd_table[fd].write_handler;
76f87348 777 fd_table[fd].write_handler = NULL;
dcfe6390 778 hdl(fd, fd_table[fd].write_data);
779 }
780 }
781}
782#endif
783
812ed90c 784static int
785fdIsHttpOrIcp(int fd)
786{
787 int j;
788 if (fd == theInIcpConnection)
789 return 1;
790 if (fd == theOutIcpConnection)
791 return 1;
792 for (j = 0; j < NHttpSockets; j++) {
793 if (fd == HttpSockets[j])
794 return 1;
795 }
796 return 0;
797}
798
f88211e8 799#if HAVE_POLL
dcfe6390 800/* poll all sockets; call handlers for those that are ready. */
801int
812ed90c 802comm_poll(time_t sec)
dcfe6390 803{
0a0bf5db 804 struct pollfd pfds[SQUID_MAXFD];
582b6456 805 PF *hdl = NULL;
dcfe6390 806 int fd;
807 int i;
808 int maxfd;
996a0a51 809 unsigned long nfds;
dcfe6390 810 int num;
dcfe6390 811 static time_t last_timeout = 0;
97c03d3c 812 static int lastinc = 0;
429fdbec 813 int poll_time;
812ed90c 814 static int incoming_counter = 0;
dcfe6390 815 time_t timeout;
dcfe6390 816 /* assume all process are very fast (less than 1 second). Call
817 * time() only once */
dcfe6390 818 /* use only 1 second granularity */
819 timeout = squid_curtime + sec;
820 do {
bbdb774b 821 if (shutdown_pending || reconfigure_pending) {
dcfe6390 822 serverConnectionsClose();
dcfe6390 823 dnsShutdownServers();
824 redirectShutdownServers();
429fdbec 825 /* shutdown_pending will be set to
826 * +1 for SIGTERM
827 * -1 for SIGINT */
bbdb774b 828 /* reconfigure_pending always == 1 when SIGHUP received */
829 if (shutdown_pending > 0 || reconfigure_pending > 0)
5c5783a2 830 setSocketShutdownLifetimes(Config.shutdownLifetime);
dcfe6390 831 else
9e4ad609 832 setSocketShutdownLifetimes(1);
dcfe6390 833 }
429fdbec 834 nfds = 0;
835 maxfd = Biggest_FD + 1;
429fdbec 836 for (i = 0; i < maxfd; i++) {
837 int events;
838 events = 0;
dcfe6390 839 /* Check each open socket for a handler. */
da2b3a17 840 if (fd_table[i].read_handler && !commDeferRead(i))
429fdbec 841 events |= POLLRDNORM;
842 if (fd_table[i].write_handler)
843 events |= POLLWRNORM;
844 if (events) {
429fdbec 845 pfds[nfds].fd = i;
846 pfds[nfds].events = events;
847 pfds[nfds].revents = 0;
848 nfds++;
055f4d4d 849 }
0b2421ea 850 }
bbdb774b 851 if (shutdown_pending || reconfigure_pending)
a3d5953d 852 debug(5, 2) ("comm_poll: Still waiting on %d FDs\n", nfds);
dcfe6390 853 if (nfds == 0)
854 return COMM_SHUTDOWN;
76f87348 855 poll_time = sec > 0 ? 1000 : 0;
0a0bf5db 856#if USE_ASYNC_IO
857 aioCheckCallbacks();
858#endif
dcfe6390 859 for (;;) {
429fdbec 860 num = poll(pfds, nfds, poll_time);
861 select_loops++;
dcfe6390 862 if (num >= 0)
863 break;
864 if (errno == EINTR)
0a0bf5db 865 continue;
a3d5953d 866 debug(5, 0) ("comm_poll: poll failure: %s\n", xstrerror());
03eb2f01 867 assert(errno != EINVAL);
dcfe6390 868 return COMM_ERROR;
869 /* NOTREACHED */
870 }
a3d5953d 871 debug(5, num ? 5 : 8) ("comm_poll: %d sockets ready\n", num);
5c5783a2 872 /* Check timeout handlers ONCE each second. */
dcfe6390 873 if (squid_curtime > last_timeout) {
874 last_timeout = squid_curtime;
875 checkTimeouts();
dcfe6390 876 }
877 if (num == 0)
878 continue;
879 /* scan each socket but the accept socket. Poll this
2c5294ce 880 * more frequently to minimize losses due to the 5 connect
dcfe6390 881 * limit in SunOS */
429fdbec 882 for (i = 0; i < nfds; i++) {
883 int revents;
884 if (((revents = pfds[i].revents) == 0) || ((fd = pfds[i].fd) == -1))
dcfe6390 885 continue;
97c03d3c 886 if ((incoming_counter++ & (lastinc > 0 ? 1 : 7)) == 0)
812ed90c 887 comm_poll_incoming();
888 if (fdIsHttpOrIcp(fd))
996a0a51 889 continue;
429fdbec 890 if (revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) {
a3d5953d 891 debug(5, 6) ("comm_poll: FD %d ready for reading\n", fd);
0b2421ea 892 if ((hdl = fd_table[fd].read_handler)) {
76f87348 893 fd_table[fd].read_handler = NULL;
0b2421ea 894 hdl(fd, fd_table[fd].read_data);
895 }
dcfe6390 896 }
429fdbec 897 if (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) {
a3d5953d 898 debug(5, 5) ("comm_poll: FD %d ready for writing\n", fd);
0b2421ea 899 if ((hdl = fd_table[fd].write_handler)) {
76f87348 900 fd_table[fd].write_handler = NULL;
0b2421ea 901 hdl(fd, fd_table[fd].write_data);
902 }
dcfe6390 903 }
429fdbec 904 if (revents & POLLNVAL) {
f1dc9b30 905 close_handler *ch;
906 close_handler *next;
76f87348 907 fde *F = &fd_table[fd];
a3d5953d 908 debug(5, 0) ("WARNING: FD %d has handlers, but it's invalid.\n", fd);
909 debug(5, 0) ("FD %d is a %s\n", fd, fdstatTypeStr[fd_table[fd].type]);
910 debug(5, 0) ("--> %s\n", fd_table[fd].desc);
911 debug(5, 0) ("tmout:%p read:%p write:%p\n",
76f87348 912 F->timeout_handler,
913 F->read_handler,
914 F->write_handler);
76f87348 915 for (ch = F->close_handler; ch; ch = ch->next)
a3d5953d 916 debug(5, 0) (" close handler: %p\n", ch->handler);
76f87348 917 if (F->close_handler) {
918 for (ch = F->close_handler; ch; ch = next) {
dcfe6390 919 next = ch->next;
920 ch->handler(fd, ch->data);
921 safe_free(ch);
922 }
76f87348 923 } else if (F->timeout_handler) {
a3d5953d 924 debug(5, 0) ("comm_poll: Calling Timeout Handler\n");
76f87348 925 F->timeout_handler(fd, F->timeout_data);
dcfe6390 926 }
76f87348 927 F->close_handler = NULL;
928 F->timeout_handler = NULL;
929 F->read_handler = NULL;
930 F->write_handler = NULL;
dcfe6390 931 }
97c03d3c 932 lastinc = polledinc;
dcfe6390 933 }
934 return COMM_OK;
97c03d3c 935 } while (timeout > squid_curtime);
a3d5953d 936 debug(5, 8) ("comm_poll: time out: %d.\n", squid_curtime);
dcfe6390 937 return COMM_TIMEOUT;
055f4d4d 938}
090089c4 939
dcfe6390 940#else
090089c4 941
942/* Select on all sockets; call handlers for those that are ready. */
b8d8561b 943int
944comm_select(time_t sec)
090089c4 945{
090089c4 946 fd_set readfds;
947 fd_set writefds;
582b6456 948 PF *hdl = NULL;
7d49daab 949 int fd;
950 int i;
951 int maxfd;
952 int nfds;
090089c4 953 int num;
97c03d3c 954 static int incoming_counter = 0;
090089c4 955 static time_t last_timeout = 0;
956 struct timeval poll_time;
97c03d3c 957 static int lastinc;
7d49daab 958 time_t timeout;
090089c4 959
960 /* assume all process are very fast (less than 1 second). Call
961 * time() only once */
090089c4 962 /* use only 1 second granularity */
b8de7ebe 963 timeout = squid_curtime + sec;
090089c4 964
f7361640 965 do {
090089c4 966 FD_ZERO(&readfds);
967 FD_ZERO(&writefds);
bbdb774b 968 if (shutdown_pending || reconfigure_pending) {
30a4f2a8 969 serverConnectionsClose();
f88bb09c 970 dnsShutdownServers();
d2af9477 971 redirectShutdownServers();
429fdbec 972 /* shutdown_pending will be set to
973 * +1 for SIGTERM
974 * -1 for SIGINT */
bbdb774b 975 /* reconfigure_pending always == 1 when SIGHUP received */
976 if (shutdown_pending > 0 || reconfigure_pending > 0)
5c5783a2 977 setSocketShutdownLifetimes(Config.shutdownLifetime);
f3753518 978 else
979 setSocketShutdownLifetimes(0);
30a4f2a8 980 }
4d64d74a 981 nfds = 0;
429fdbec 982 maxfd = Biggest_FD + 1;
4d64d74a 983 for (i = 0; i < maxfd; i++) {
090089c4 984 /* Check each open socket for a handler. */
da2b3a17 985 if (fd_table[i].read_handler && !commDeferRead(i)) {
4d64d74a 986 nfds++;
090089c4 987 FD_SET(i, &readfds);
4d64d74a 988 }
989 if (fd_table[i].write_handler) {
990 nfds++;
090089c4 991 FD_SET(i, &writefds);
4d64d74a 992 }
090089c4 993 }
bbdb774b 994 if (shutdown_pending || reconfigure_pending)
a3d5953d 995 debug(5, 2) ("comm_select: Still waiting on %d FDs\n", nfds);
4d64d74a 996 if (nfds == 0)
997 return COMM_SHUTDOWN;
0a0bf5db 998#if USE_ASYNC_IO
999 aioCheckCallbacks();
1000#endif
7690e8eb 1001 for (;;) {
89fb2544 1002 poll_time.tv_sec = sec > 0 ? 1 : 0;
090089c4 1003 poll_time.tv_usec = 0;
d0217c9b 1004 num = select(maxfd, &readfds, &writefds, NULL, &poll_time);
429fdbec 1005 select_loops++;
090089c4 1006 if (num >= 0)
1007 break;
4d64d74a 1008 if (errno == EINTR)
1009 break;
a3d5953d 1010 debug(50, 0) ("comm_select: select failure: %s\n",
30a4f2a8 1011 xstrerror());
d0217c9b 1012 examine_select(&readfds, &writefds);
bf9f8f2b 1013 return COMM_ERROR;
30a4f2a8 1014 /* NOTREACHED */
090089c4 1015 }
4d64d74a 1016 if (num < 0)
1017 continue;
a3d5953d 1018 debug(5, num ? 5 : 8) ("comm_select: %d sockets ready at %d\n",
30a4f2a8 1019 num, (int) squid_curtime);
090089c4 1020
1021 /* Check lifetime and timeout handlers ONCE each second.
1022 * Replaces brain-dead check every time through the loop! */
b8de7ebe 1023 if (squid_curtime > last_timeout) {
1024 last_timeout = squid_curtime;
090089c4 1025 checkTimeouts();
090089c4 1026 }
7d49daab 1027 if (num == 0)
1028 continue;
1029
090089c4 1030 /* scan each socket but the accept socket. Poll this
2c5294ce 1031 * more frequently to minimize losses due to the 5 connect
090089c4 1032 * limit in SunOS */
1033
5742d7c9 1034 for (fd = 0; fd < maxfd; fd++) {
d0217c9b 1035 if (!FD_ISSET(fd, &readfds) && !FD_ISSET(fd, &writefds))
7d49daab 1036 continue;
cb2f803a 1037 if ((incoming_counter++ & (lastinc > 0 ? 1 : 7)) == 0)
1038 comm_select_incoming();
812ed90c 1039 if (fdIsHttpOrIcp(fd))
7d49daab 1040 continue;
7d49daab 1041 if (FD_ISSET(fd, &readfds)) {
a3d5953d 1042 debug(5, 6) ("comm_select: FD %d ready for reading\n", fd);
7d49daab 1043 if (fd_table[fd].read_handler) {
ff8d0ea6 1044 hdl = fd_table[fd].read_handler;
76f87348 1045 fd_table[fd].read_handler = NULL;
ff8d0ea6 1046 hdl(fd, fd_table[fd].read_data);
090089c4 1047 }
7d49daab 1048 }
1049 if (FD_ISSET(fd, &writefds)) {
a3d5953d 1050 debug(5, 5) ("comm_select: FD %d ready for writing\n", fd);
7d49daab 1051 if (fd_table[fd].write_handler) {
ff8d0ea6 1052 hdl = fd_table[fd].write_handler;
76f87348 1053 fd_table[fd].write_handler = NULL;
ff8d0ea6 1054 hdl(fd, fd_table[fd].write_data);
090089c4 1055 }
7d49daab 1056 }
97c03d3c 1057 lastinc = polledinc;
090089c4 1058 }
7d49daab 1059 return COMM_OK;
97c03d3c 1060 } while (timeout > squid_curtime);
a3d5953d 1061 debug(5, 8) ("comm_select: time out: %d.\n", squid_curtime);
090089c4 1062 return COMM_TIMEOUT;
1063}
dcfe6390 1064#endif
090089c4 1065
b8d8561b 1066void
582b6456 1067commSetSelect(int fd, unsigned int type, PF * handler, void *client_data, time_t timeout)
090089c4 1068{
89de058c 1069 fde *F = &fd_table[fd];
489b22c1 1070 assert(fd >= 0);
89de058c 1071 assert(F->open == FD_OPEN);
cebe3f19 1072 debug(5, 5) ("commSetSelect: FD %d type %d\n", fd, type);
090089c4 1073 if (type & COMM_SELECT_READ) {
76f87348 1074 F->read_handler = handler;
1075 F->read_data = client_data;
090089c4 1076 }
1077 if (type & COMM_SELECT_WRITE) {
76f87348 1078 F->write_handler = handler;
1079 F->write_data = client_data;
090089c4 1080 }
5c5783a2 1081 if (timeout)
76f87348 1082 F->timeout = squid_curtime + timeout;
090089c4 1083}
1084
b8d8561b 1085void
582b6456 1086comm_add_close_handler(int fd, PF * handler, void *data)
30a4f2a8 1087{
f1dc9b30 1088 close_handler *new = xmalloc(sizeof(*new));
a3d5953d 1089 debug(5, 5) ("comm_add_close_handler: FD %d, handler=%p, data=%p\n",
e0c42e90 1090 fd, handler, data);
30a4f2a8 1091 new->handler = handler;
1092 new->data = data;
1093 new->next = fd_table[fd].close_handler;
1094 fd_table[fd].close_handler = new;
603a02fd 1095 cbdataLock(data);
30a4f2a8 1096}
1097
b8d8561b 1098void
582b6456 1099comm_remove_close_handler(int fd, PF * handler, void *data)
090089c4 1100{
f1dc9b30 1101 close_handler *p;
1102 close_handler *last = NULL;
30a4f2a8 1103 /* Find handler in list */
1104 for (p = fd_table[fd].close_handler; p != NULL; last = p, p = p->next)
1105 if (p->handler == handler && p->data == data)
1106 break; /* This is our handler */
f88211e8 1107 assert(p != NULL);
30a4f2a8 1108 /* Remove list entry */
1109 if (last)
1110 last->next = p->next;
1111 else
1112 fd_table[fd].close_handler = p->next;
1113 safe_free(p);
1114}
090089c4 1115
b8d8561b 1116static void
1117commSetNoLinger(int fd)
30a4f2a8 1118{
1119 struct linger L;
090089c4 1120 L.l_onoff = 0; /* off */
1121 L.l_linger = 0;
30a4f2a8 1122 if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &L, sizeof(L)) < 0)
a3d5953d 1123 debug(50, 0) ("commSetNoLinger: FD %d: %s\n", fd, xstrerror());
090089c4 1124}
1125
b8d8561b 1126static void
1127commSetReuseAddr(int fd)
090089c4 1128{
1129 int on = 1;
30a4f2a8 1130 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0)
a3d5953d 1131 debug(50, 1) ("commSetReuseAddr: FD %d: %s\n", fd, xstrerror());
090089c4 1132}
1133
b8d8561b 1134static void
1135commSetTcpRcvbuf(int fd, int size)
f868539a 1136{
1137 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *) &size, sizeof(size)) < 0)
a3d5953d 1138 debug(50, 1) ("commSetTcpRcvbuf: FD %d, SIZE %d: %s\n",
b6f794d6 1139 fd, size, xstrerror());
f868539a 1140}
1141
b8d8561b 1142int
1143commSetNonBlocking(int fd)
30a4f2a8 1144{
731e4d49 1145 int flags;
9e205701 1146 int dummy = 0;
95cf2361 1147 if ((flags = fcntl(fd, F_GETFL, dummy)) < 0) {
a3d5953d 1148 debug(50, 0) ("FD %d: fcntl F_GETFL: %s\n", fd, xstrerror());
731e4d49 1149 return COMM_ERROR;
1150 }
4f92c80c 1151 if (fcntl(fd, F_SETFL, flags | SQUID_NONBLOCK) < 0) {
a3d5953d 1152 debug(50, 0) ("commSetNonBlocking: FD %d: %s\n", fd, xstrerror());
30a4f2a8 1153 return COMM_ERROR;
090089c4 1154 }
090089c4 1155 return 0;
1156}
1157
b8d8561b 1158void
1159commSetCloseOnExec(int fd)
3ca60c86 1160{
1161#ifdef FD_CLOEXEC
731e4d49 1162 int flags;
7a18b487 1163 int dummy = 0;
c7989865 1164 if ((flags = fcntl(fd, F_GETFL, dummy)) < 0) {
a3d5953d 1165 debug(50, 0) ("FD %d: fcntl F_GETFL: %s\n", fd, xstrerror());
24382924 1166 return;
3ca60c86 1167 }
24382924 1168 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
a3d5953d 1169 debug(50, 0) ("FD %d: set close-on-exec failed: %s\n", fd, xstrerror());
3ca60c86 1170#endif
1171}
1172
e90100aa 1173#ifdef TCP_NODELAY
1174static void
1175commSetTcpNoDelay(int fd)
1176{
1177 int on = 1;
1178 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on)) < 0)
a3d5953d 1179 debug(50, 1) ("commSetTcpNoDelay: FD %d: %s\n", fd, xstrerror());
e90100aa 1180}
1181#endif
1182
b8d8561b 1183int
0673c0ba 1184comm_init(void)
090089c4 1185{
f1dc9b30 1186 fd_table = xcalloc(Squid_MaxFD, sizeof(fde));
1187 meta_data.misc += Squid_MaxFD * sizeof(fde);
090089c4 1188 /* Keep a few file descriptors free so that we don't run out of FD's
1189 * after accepting a client but before it opens a socket or a file.
e83892e9 1190 * Since Squid_MaxFD can be as high as several thousand, don't waste them */
1191 RESERVED_FD = min(100, Squid_MaxFD / 4);
090089c4 1192 /* hardwired lifetimes */
e83892e9 1193 meta_data.misc += Squid_MaxFD * sizeof(int);
055f4d4d 1194 zero_tv.tv_sec = 0;
1195 zero_tv.tv_usec = 0;
090089c4 1196 return 0;
1197}
1198
1199
f88211e8 1200#if !HAVE_POLL
090089c4 1201/*
1202 * examine_select - debug routine.
1203 *
1204 * I spend the day chasing this core dump that occurs when both the client
1205 * and the server side of a cache fetch simultaneoulsy abort the
1206 * connection. While I haven't really studied the code to figure out how
1207 * it happens, the snippet below may prevent the cache from exitting:
1208 *
1209 * Call this from where the select loop fails.
1210 */
b8d8561b 1211static int
5742d7c9 1212examine_select(fd_set * readfds, fd_set * writefds)
090089c4 1213{
1214 int fd = 0;
bbc5ea8f 1215 fd_set read_x;
1216 fd_set write_x;
090089c4 1217 int num;
1218 struct timeval tv;
f1dc9b30 1219 close_handler *ch = NULL;
1220 close_handler *next = NULL;
76f87348 1221 fde *F = NULL;
090089c4 1222
a3d5953d 1223 debug(5, 0) ("examine_select: Examining open file descriptors...\n");
e83892e9 1224 for (fd = 0; fd < Squid_MaxFD; fd++) {
090089c4 1225 FD_ZERO(&read_x);
1226 FD_ZERO(&write_x);
090089c4 1227 tv.tv_sec = tv.tv_usec = 0;
af00901c 1228 if (FD_ISSET(fd, readfds))
090089c4 1229 FD_SET(fd, &read_x);
af00901c 1230 else if (FD_ISSET(fd, writefds))
1231 FD_SET(fd, &write_x);
af00901c 1232 else
1233 continue;
e83892e9 1234 num = select(Squid_MaxFD, &read_x, &write_x, NULL, &tv);
af00901c 1235 if (num > -1) {
a3d5953d 1236 debug(5, 5) ("FD %d is valid.\n", fd);
af00901c 1237 continue;
1238 }
76f87348 1239 F = &fd_table[fd];
a3d5953d 1240 debug(5, 0) ("FD %d: %s\n", fd, xstrerror());
1241 debug(5, 0) ("WARNING: FD %d has handlers, but it's invalid.\n", fd);
1242 debug(5, 0) ("FD %d is a %s called '%s'\n",
ca98227c 1243 fd,
95d15928 1244 fdstatTypeStr[fd_table[fd].type],
76f87348 1245 F->desc);
a3d5953d 1246 debug(5, 0) ("tmout:%p read:%p write:%p\n",
76f87348 1247 F->timeout_handler,
1248 F->read_handler,
1249 F->write_handler);
1250 for (ch = F->close_handler; ch; ch = ch->next)
a3d5953d 1251 debug(5, 0) (" close handler: %p\n", ch->handler);
76f87348 1252 if (F->close_handler) {
1253 for (ch = F->close_handler; ch; ch = next) {
af00901c 1254 next = ch->next;
1255 ch->handler(fd, ch->data);
1256 safe_free(ch);
090089c4 1257 }
76f87348 1258 } else if (F->timeout_handler) {
a3d5953d 1259 debug(5, 0) ("examine_select: Calling Timeout Handler\n");
76f87348 1260 F->timeout_handler(fd, F->timeout_data);
090089c4 1261 }
76f87348 1262 F->close_handler = NULL;
1263 F->timeout_handler = NULL;
1264 F->read_handler = NULL;
1265 F->write_handler = NULL;
af00901c 1266 FD_CLR(fd, readfds);
1267 FD_CLR(fd, writefds);
090089c4 1268 }
090089c4 1269 return 0;
1270}
dcfe6390 1271#endif
090089c4 1272
b8d8561b 1273static void
0673c0ba 1274checkTimeouts(void)
090089c4 1275{
1276 int fd;
76f87348 1277 fde *F = NULL;
5c5783a2 1278 PF *callback;
429fdbec 1279 for (fd = 0; fd <= Biggest_FD; fd++) {
76f87348 1280 F = &fd_table[fd];
1281 if (F->open != FD_OPEN)
429fdbec 1282 continue;
76f87348 1283 if (F->timeout == 0)
30a4f2a8 1284 continue;
76f87348 1285 if (F->timeout > squid_curtime)
30a4f2a8 1286 continue;
a3d5953d 1287 debug(5, 5) ("checkTimeouts: FD %d Expired\n", fd);
76f87348 1288 if (F->timeout_handler) {
a3d5953d 1289 debug(5, 5) ("checkTimeouts: FD %d: Call timeout handler\n", fd);
76f87348 1290 callback = F->timeout_handler;
1291 F->timeout_handler = NULL;
1292 callback(fd, F->timeout_data);
30a4f2a8 1293 } else {
a3d5953d 1294 debug(5, 5) ("checkTimeouts: FD %d: Forcing comm_close()\n", fd);
30a4f2a8 1295 comm_close(fd);
090089c4 1296 }
1297 }
1298}
1299
30a4f2a8 1300/* Write to FD. */
b8d8561b 1301static void
582b6456 1302commHandleWrite(int fd, void *data)
30a4f2a8 1303{
f17936ab 1304 CommWriteStateData *state = data;
30a4f2a8 1305 int len = 0;
1306 int nleft;
1307
cebe3f19 1308 debug(5, 5) ("commHandleWrite: FD %d: off %d, sz %d.\n",
1309 fd, state->offset, state->size);
30a4f2a8 1310
1311 nleft = state->size - state->offset;
1312 len = write(fd, state->buf + state->offset, nleft);
b69f7771 1313 fd_bytes(fd, len, FD_WRITE);
30a4f2a8 1314
1315 if (len == 0) {
1316 /* Note we even call write if nleft == 0 */
1317 /* We're done */
1318 if (nleft != 0)
02be0294 1319 debug(5, 1) ("commHandleWrite: FD %d: write failure: connection closed with %d bytes remaining.\n", fd, nleft);
f17936ab 1320 CommWriteStateCallbackAndFree(fd, nleft ? COMM_ERROR : COMM_OK);
30a4f2a8 1321 } else if (len < 0) {
1322 /* An error */
26a880e2 1323 if (ignoreErrno(errno)) {
a3d5953d 1324 debug(50, 10) ("commHandleWrite: FD %d: write failure: %s.\n",
30a4f2a8 1325 fd, xstrerror());
b177367b 1326 commSetSelect(fd,
30a4f2a8 1327 COMM_SELECT_WRITE,
cd1fb0eb 1328 commHandleWrite,
b177367b 1329 state,
85d7ea98 1330 0);
9864ee44 1331 } else {
a3d5953d 1332 debug(50, 2) ("commHandleWrite: FD %d: write failure: %s.\n",
9864ee44 1333 fd, xstrerror());
f17936ab 1334 CommWriteStateCallbackAndFree(fd, COMM_ERROR);
30a4f2a8 1335 }
30a4f2a8 1336 } else {
1337 /* A successful write, continue */
1338 state->offset += len;
1339 if (state->offset < state->size) {
1340 /* Not done, reinstall the write handler and write some more */
b177367b 1341 commSetSelect(fd,
30a4f2a8 1342 COMM_SELECT_WRITE,
cd1fb0eb 1343 commHandleWrite,
b177367b 1344 state,
85d7ea98 1345 0);
9864ee44 1346 } else {
f17936ab 1347 CommWriteStateCallbackAndFree(fd, COMM_OK);
30a4f2a8 1348 }
30a4f2a8 1349 }
1350}
1351
1352
1353
1354/* Select for Writing on FD, until SIZE bytes are sent. Call
1355 * * HANDLER when complete. */
b8d8561b 1356void
9e4ad609 1357comm_write(int fd, char *buf, int size, CWCB * handler, void *handler_data, FREE * free_func)
30a4f2a8 1358{
f17936ab 1359 CommWriteStateData *state = NULL;
a3d5953d 1360 debug(5, 5) ("comm_write: FD %d: sz %d: hndl %p: data %p.\n",
787869c5 1361 fd, size, handler, handler_data);
03eb2f01 1362 assert(fd_table[fd].rwstate == NULL);
f17936ab 1363 state = xcalloc(1, sizeof(CommWriteStateData));
30a4f2a8 1364 state->buf = buf;
1365 state->size = size;
1366 state->offset = 0;
1367 state->handler = handler;
30a4f2a8 1368 state->handler_data = handler_data;
86ee2017 1369 state->free = free_func;
a56a3abe 1370 fd_table[fd].rwstate = state;
1a8f5ed6 1371 cbdataLock(handler_data);
b177367b 1372 commSetSelect(fd,
30a4f2a8 1373 COMM_SELECT_WRITE,
cd1fb0eb 1374 commHandleWrite,
b177367b 1375 fd_table[fd].rwstate,
1376 0);
30a4f2a8 1377}
26a880e2 1378
1379static int
1380ignoreErrno(int errno)
1381{
1382 if (errno == EWOULDBLOCK)
1383 return 1;
1384#if EAGAIN != EWOULDBLOCK
1385 if (errno == EAGAIN)
1386 return 1;
1387#endif
1388 if (errno == EALREADY)
1389 return 1;
1390 if (errno == EINTR)
1391 return 1;
1392 return 0;
1393}