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