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