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