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