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