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