]> git.ipfire.org Git - thirdparty/squid.git/blame - src/comm.cc
Oops.. deny_info_url introduces a completely wild array dereference
[thirdparty/squid.git] / src / comm.cc
CommitLineData
da2b3a17 1
30a4f2a8 2/*
a3fa14bf 3 * $Id: comm.cc,v 1.330 2002/04/18 16:09:37 hno Exp $
30a4f2a8 4 *
5 * DEBUG: section 5 Socket Functions
6 * AUTHOR: Harvest Derived
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 9 * ----------------------------------------------------------
30a4f2a8 10 *
2b6662ba 11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
30a4f2a8 19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
cbdec147 32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 33 *
30a4f2a8 34 */
090089c4 35
44a47c6e 36#include "squid.h"
090089c4 37
b671cc68 38#if defined(_SQUID_CYGWIN_)
39#include <sys/ioctl.h>
40#endif
30a4f2a8 41#ifdef HAVE_NETINET_TCP_H
42#include <netinet/tcp.h>
43#endif
090089c4 44
f88211e8 45typedef struct {
46 char *host;
47 u_short port;
48 struct sockaddr_in S;
49 CNCB *callback;
50 void *data;
f88211e8 51 struct in_addr in_addr;
52 int locks;
03a1ee42 53 int fd;
22c653cd 54 int tries;
55 int addrcount;
56 int connstart;
f88211e8 57} ConnectStateData;
58
090089c4 59/* STATIC */
f5b8bbc4 60static int commBind(int s, struct in_addr, u_short port);
f5b8bbc4 61static void commSetReuseAddr(int);
62static void commSetNoLinger(int);
f5b8bbc4 63static void CommWriteStateCallbackAndFree(int fd, int code);
30a4f2a8 64#ifdef TCP_NODELAY
f5b8bbc4 65static void commSetTcpNoDelay(int);
30a4f2a8 66#endif
f5b8bbc4 67static void commSetTcpRcvbuf(int, int);
f88211e8 68static PF commConnectFree;
03a1ee42 69static PF commConnectHandle;
70static PF commHandleWrite;
edeb28fd 71static IPH commConnectDnsHandle;
f5b8bbc4 72static void commConnectCallback(ConnectStateData * cs, int status);
22c653cd 73static int commResetFD(ConnectStateData * cs);
74static int commRetryConnect(ConnectStateData * cs);
28c60158 75CBDATA_TYPE(ConnectStateData);
723123a9 76
77static MemPool *comm_write_pool = NULL;
58cd5bbd 78static MemPool *conn_close_pool = NULL;
309ad3b6 79
b8d8561b 80static void
f17936ab 81CommWriteStateCallbackAndFree(int fd, int code)
9864ee44 82{
f17936ab 83 CommWriteStateData *CommWriteState = fd_table[fd].rwstate;
84 CWCB *callback = NULL;
fa80a8ef 85 void *cbdata;
a56a3abe 86 fd_table[fd].rwstate = NULL;
f17936ab 87 if (CommWriteState == NULL)
9864ee44 88 return;
c0dec081 89 if (CommWriteState->free_func) {
729dd65c 90 FREE *free_func = CommWriteState->free_func;
91 void *free_buf = CommWriteState->buf;
92 CommWriteState->free_func = NULL;
f17936ab 93 CommWriteState->buf = NULL;
729dd65c 94 free_func(free_buf);
9864ee44 95 }
f17936ab 96 callback = CommWriteState->handler;
97 CommWriteState->handler = NULL;
fa80a8ef 98 if (callback && cbdataReferenceValidDone(CommWriteState->handler_data, &cbdata))
99 callback(fd, CommWriteState->buf, CommWriteState->offset, code, cbdata);
723123a9 100 memPoolFree(comm_write_pool, CommWriteState);
9864ee44 101}
102
090089c4 103/* Return the local port associated with fd. */
b8d8561b 104u_short
105comm_local_port(int fd)
090089c4 106{
107 struct sockaddr_in addr;
6637e3a5 108 socklen_t addr_len = 0;
76f87348 109 fde *F = &fd_table[fd];
090089c4 110
090089c4 111 /* If the fd is closed already, just return */
60c0b5a2 112 if (!F->flags.open) {
a3d5953d 113 debug(5, 0) ("comm_local_port: FD %d has been closed.\n", fd);
30a4f2a8 114 return 0;
090089c4 115 }
76f87348 116 if (F->local_port)
117 return F->local_port;
090089c4 118 addr_len = sizeof(addr);
119 if (getsockname(fd, (struct sockaddr *) &addr, &addr_len)) {
a3d5953d 120 debug(50, 1) ("comm_local_port: Failed to retrieve TCP/UDP port number for socket: FD %d: %s\n", fd, xstrerror());
30a4f2a8 121 return 0;
090089c4 122 }
76f87348 123 F->local_port = ntohs(addr.sin_port);
5f6ac48b 124 debug(5, 6) ("comm_local_port: FD %d: port %d\n", fd, (int) F->local_port);
76f87348 125 return F->local_port;
090089c4 126}
127
b8d8561b 128static int
129commBind(int s, struct in_addr in_addr, u_short port)
090089c4 130{
131 struct sockaddr_in S;
090089c4 132
090089c4 133 memset(&S, '\0', sizeof(S));
134 S.sin_family = AF_INET;
135 S.sin_port = htons(port);
30a4f2a8 136 S.sin_addr = in_addr;
83704487 137 statCounter.syscalls.sock.binds++;
090089c4 138 if (bind(s, (struct sockaddr *) &S, sizeof(S)) == 0)
139 return COMM_OK;
a3d5953d 140 debug(50, 0) ("commBind: Cannot bind socket FD %d to %s:%d: %s\n",
090089c4 141 s,
30a4f2a8 142 S.sin_addr.s_addr == INADDR_ANY ? "*" : inet_ntoa(S.sin_addr),
44a62238 143 (int) port,
144 xstrerror());
090089c4 145 return COMM_ERROR;
146}
147
148/* Create a socket. Default is blocking, stream (TCP) socket. IO_TYPE
d6827718 149 * is OR of flags specified in comm.h. Defaults TOS */
b8d8561b 150int
16b204c4 151comm_open(int sock_type,
cc6a9d2e 152 int proto,
153 struct in_addr addr,
154 u_short port,
155 int flags,
0ee4272b 156 const char *note)
d6827718 157{
158 return comm_openex(sock_type, proto, addr, port, flags, 0, note);
159}
160
161
162/* Create a socket. Default is blocking, stream (TCP) socket. IO_TYPE
163 * is OR of flags specified in defines.h:COMM_* */
164int
165comm_openex(int sock_type,
166 int proto,
167 struct in_addr addr,
168 u_short port,
169 int flags,
170 unsigned char TOS,
171 const char *note)
090089c4 172{
173 int new_socket;
9056f553 174 int tos = 0;
76f87348 175 fde *F = NULL;
090089c4 176
177 /* Create socket for accepting new connections. */
83704487 178 statCounter.syscalls.sock.sockets++;
16b204c4 179 if ((new_socket = socket(AF_INET, sock_type, proto)) < 0) {
090089c4 180 /* Increase the number of reserved fd's if calls to socket()
181 * are failing because the open file table is full. This
182 * limits the number of simultaneous clients */
183 switch (errno) {
184 case ENFILE:
185 case EMFILE:
a3d5953d 186 debug(50, 1) ("comm_open: socket failure: %s\n", xstrerror());
9bc73deb 187 fdAdjustReserved();
090089c4 188 break;
189 default:
a3d5953d 190 debug(50, 0) ("comm_open: socket failure: %s\n", xstrerror());
090089c4 191 }
603a02fd 192 return -1;
090089c4 193 }
d6827718 194 /* set TOS if needed */
195 if (TOS) {
196#ifdef IP_TOS
197 tos = TOS;
198 if (setsockopt(new_socket, IPPROTO_IP, IP_TOS, (char *) &tos, sizeof(int)) < 0)
199 debug(50, 1) ("comm_open: setsockopt(IP_TOS) on FD %d: %s\n",
200 new_socket, xstrerror());
201#else
202 debug(50, 0) ("comm_open: setsockopt(IP_TOS) not supported on this platform\n");
203#endif
204 }
090089c4 205 /* update fdstat */
365e5b34 206 debug(5, 5) ("comm_open: FD %d is a new socket\n", new_socket);
5c5783a2 207 fd_open(new_socket, FD_SOCKET, note);
76f87348 208 F = &fd_table[new_socket];
d6827718 209 F->local_addr = addr;
210 F->tos = tos;
79a15e0a 211 if (!(flags & COMM_NOCLOEXEC))
3ca60c86 212 commSetCloseOnExec(new_socket);
cdc33f35 213 if ((flags & COMM_REUSEADDR))
214 commSetReuseAddr(new_socket);
7690e8eb 215 if (port > (u_short) 0) {
30a4f2a8 216 commSetNoLinger(new_socket);
3b4be6a6 217 if (opt_reuseaddr)
090089c4 218 commSetReuseAddr(new_socket);
090089c4 219 }
a3724d50 220 if (addr.s_addr != no_addr.s_addr) {
221 if (commBind(new_socket, addr, port) != COMM_OK) {
222 comm_close(new_socket);
603a02fd 223 return -1;
a3724d50 224 }
23ff6968 225 }
76f87348 226 F->local_port = port;
090089c4 227
79a15e0a 228 if (flags & COMM_NONBLOCKING)
30a4f2a8 229 if (commSetNonBlocking(new_socket) == COMM_ERROR)
603a02fd 230 return -1;
30a4f2a8 231#ifdef TCP_NODELAY
232 if (sock_type == SOCK_STREAM)
233 commSetTcpNoDelay(new_socket);
234#endif
1241e63e 235 if (Config.tcpRcvBufsz > 0 && sock_type == SOCK_STREAM)
236 commSetTcpRcvbuf(new_socket, Config.tcpRcvBufsz);
090089c4 237 return new_socket;
238}
239
b4ea1f2e 240/*
241 * NOTE: set the listen queue to Squid_MaxFD/4 and rely on the kernel to
242 * impose an upper limit. Solaris' listen(3n) page says it has
243 * no limit on this parameter, but sys/socket.h sets SOMAXCONN
244 * to 5. HP-UX currently has a limit of 20. SunOS is 5 and
245 * OSF 3.0 is 8.
246 */
b8d8561b 247int
248comm_listen(int sock)
090089c4 249{
250 int x;
e83892e9 251 if ((x = listen(sock, Squid_MaxFD >> 2)) < 0) {
a3d5953d 252 debug(50, 0) ("comm_listen: listen(%d, %d): %s\n",
e83892e9 253 Squid_MaxFD >> 2,
090089c4 254 sock, xstrerror());
255 return x;
256 }
257 return sock;
258}
259
e5f6c5c2 260void
4f92c80c 261commConnectStart(int fd, const char *host, u_short port, CNCB * callback, void *data)
e924600d 262{
28c60158 263 ConnectStateData *cs;
6a988308 264 debug(5, 3) ("commConnectStart: FD %d, %s:%d\n", fd, host, (int) port);
72711e31 265 cs = cbdataAlloc(ConnectStateData);
03a1ee42 266 cs->fd = fd;
e924600d 267 cs->host = xstrdup(host);
268 cs->port = port;
269 cs->callback = callback;
fa80a8ef 270 cs->data = cbdataReference(data);
e924600d 271 comm_add_close_handler(fd, commConnectFree, cs);
f88211e8 272 cs->locks++;
8407afee 273 ipcache_nbgethostbyname(host, commConnectDnsHandle, cs);
edeb28fd 274}
275
276static void
03a1ee42 277commConnectDnsHandle(const ipcache_addrs * ia, void *data)
edeb28fd 278{
279 ConnectStateData *cs = data;
f88211e8 280 assert(cs->locks == 1);
281 cs->locks--;
edeb28fd 282 if (ia == NULL) {
a3d5953d 283 debug(5, 3) ("commConnectDnsHandle: Unknown host: %s\n", cs->host);
6cf028ab 284 if (!dns_error_message) {
285 dns_error_message = "Unknown DNS error";
0e473d70 286 debug(5, 1) ("commConnectDnsHandle: Bad dns_error_message\n");
6cf028ab 287 }
a64c2869 288 assert(dns_error_message != NULL);
03a1ee42 289 commConnectCallback(cs, COMM_ERR_DNS);
edeb28fd 290 return;
291 }
f076b37b 292 assert(ia->cur < ia->count);
edeb28fd 293 cs->in_addr = ia->in_addrs[ia->cur];
52926044 294 ipcacheCycleAddr(cs->host, NULL);
22c653cd 295 cs->addrcount = ia->count;
296 cs->connstart = squid_curtime;
03a1ee42 297 commConnectHandle(cs->fd, cs);
e924600d 298}
299
f88211e8 300static void
03a1ee42 301commConnectCallback(ConnectStateData * cs, int status)
f88211e8 302{
a3d5953d 303 CNCB *callback = cs->callback;
fa80a8ef 304 void *cbdata = cs->data;
03a1ee42 305 int fd = cs->fd;
a3d5953d 306 comm_remove_close_handler(fd, commConnectFree, cs);
9daca08e 307 cs->callback = NULL;
308 cs->data = NULL;
e1b16349 309 commSetTimeout(fd, -1, NULL, NULL);
a3d5953d 310 commConnectFree(fd, cs);
fa80a8ef 311 if (cbdataReferenceValid(cbdata))
312 callback(fd, status, cbdata);
f88211e8 313}
314
e924600d 315static void
9daca08e 316commConnectFree(int fd, void *data)
e924600d 317{
318 ConnectStateData *cs = data;
9daca08e 319 debug(5, 3) ("commConnectFree: FD %d\n", fd);
fa80a8ef 320 cbdataReferenceDone(cs->data);
8407afee 321 safe_free(cs->host);
322 cbdataFree(cs);
e924600d 323}
324
22c653cd 325/* Reset FD so that we can connect() again */
edeb28fd 326static int
22c653cd 327commResetFD(ConnectStateData * cs)
edeb28fd 328{
329 int fd2;
d6827718 330 fde *F;
fa80a8ef 331 if (!cbdataReferenceValid(cs->data))
7dd44885 332 return 0;
83704487 333 statCounter.syscalls.sock.sockets++;
edeb28fd 334 fd2 = socket(AF_INET, SOCK_STREAM, 0);
83704487 335 statCounter.syscalls.sock.sockets++;
edeb28fd 336 if (fd2 < 0) {
22c653cd 337 debug(5, 0) ("commResetFD: socket: %s\n", xstrerror());
9bc73deb 338 if (ENFILE == errno || EMFILE == errno)
339 fdAdjustReserved();
edeb28fd 340 return 0;
341 }
22c653cd 342 if (dup2(fd2, cs->fd) < 0) {
343 debug(5, 0) ("commResetFD: dup2: %s\n", xstrerror());
9bc73deb 344 if (ENFILE == errno || EMFILE == errno)
345 fdAdjustReserved();
d6827718 346 close(fd2);
edeb28fd 347 return 0;
348 }
edeb28fd 349 close(fd2);
d6827718 350 F = &fd_table[cs->fd];
b5568a61 351 fd_table[cs->fd].flags.called_connect = 0;
09544acc 352 /*
353 * yuck, this has assumptions about comm_open() arguments for
354 * the original socket
355 */
d6827718 356 if (commBind(cs->fd, F->local_addr, F->local_port) != COMM_OK) {
357 debug(5, 0) ("commResetFD: bind: %s\n", xstrerror());
358 return 0;
09544acc 359 }
d6827718 360#ifdef IP_TOS
361 if (F->tos) {
362 int tos = F->tos;
363 if (setsockopt(cs->fd, IPPROTO_IP, IP_TOS, (char *) &tos, sizeof(int)) < 0)
364 debug(50, 1) ("commResetFD: setsockopt(IP_TOS) on FD %d: %s\n", cs->fd, xstrerror());
365 }
366#endif
367 if (F->flags.close_on_exec)
368 commSetCloseOnExec(cs->fd);
369 if (F->flags.nonblocking)
370 commSetNonBlocking(cs->fd);
09544acc 371#ifdef TCP_NODELAY
d6827718 372 if (F->flags.nodelay)
373 commSetTcpNoDelay(cs->fd);
09544acc 374#endif
375 if (Config.tcpRcvBufsz > 0)
376 commSetTcpRcvbuf(cs->fd, Config.tcpRcvBufsz);
edeb28fd 377 return 1;
378}
379
22c653cd 380static int
381commRetryConnect(ConnectStateData * cs)
382{
383 assert(cs->addrcount > 0);
384 if (cs->addrcount == 1) {
385 if (cs->tries >= Config.retry.maxtries)
386 return 0;
387 if (squid_curtime - cs->connstart > Config.Timeout.connect)
388 return 0;
22c653cd 389 } else {
390 if (cs->tries > cs->addrcount)
391 return 0;
392 }
393 return commResetFD(cs);
394}
395
e924600d 396/* Connect SOCK to specified DEST_PORT at DEST_HOST. */
397static void
398commConnectHandle(int fd, void *data)
090089c4 399{
f88211e8 400 ConnectStateData *cs = data;
401 if (cs->S.sin_addr.s_addr == 0) {
402 cs->S.sin_family = AF_INET;
403 cs->S.sin_addr = cs->in_addr;
404 cs->S.sin_port = htons(cs->port);
17a0a4ee 405 if (Config.onoff.log_fqdn)
f88211e8 406 fqdncache_gethostbyaddr(cs->S.sin_addr, FQDN_LOOKUP_IF_MISS);
e5f6c5c2 407 }
f88211e8 408 switch (comm_connect_addr(fd, &cs->S)) {
e5f6c5c2 409 case COMM_INPROGRESS:
11994bb9 410 debug(5, 5) ("commConnectHandle: FD %d: COMM_INPROGRESS\n", fd);
f88211e8 411 commSetSelect(fd, COMM_SELECT_WRITE, commConnectHandle, cs, 0);
e5f6c5c2 412 break;
413 case COMM_OK:
22c653cd 414 ipcacheMarkGoodAddr(cs->host, cs->S.sin_addr);
03a1ee42 415 commConnectCallback(cs, COMM_OK);
e5f6c5c2 416 break;
417 default:
22c653cd 418 cs->tries++;
419 ipcacheMarkBadAddr(cs->host, cs->S.sin_addr);
194dd3b8 420 if (Config.onoff.test_reachability)
421 netdbDeleteAddrNetwork(cs->S.sin_addr);
22c653cd 422 if (commRetryConnect(cs)) {
f88211e8 423 cs->locks++;
8407afee 424 ipcache_nbgethostbyname(cs->host, commConnectDnsHandle, cs);
edeb28fd 425 } else {
03a1ee42 426 commConnectCallback(cs, COMM_ERR_CONNECT);
edeb28fd 427 }
e5f6c5c2 428 break;
090089c4 429 }
090089c4 430}
22c653cd 431
b8d8561b 432int
4f92c80c 433commSetTimeout(int fd, int timeout, PF * handler, void *data)
090089c4 434{
76f87348 435 fde *F;
a3d5953d 436 debug(5, 3) ("commSetTimeout: FD %d timeout %d\n", fd, timeout);
03eb2f01 437 assert(fd >= 0);
438 assert(fd < Squid_MaxFD);
76f87348 439 F = &fd_table[fd];
60c0b5a2 440 assert(F->flags.open);
5c5783a2 441 if (timeout < 0) {
a3fa14bf 442 cbdataReferenceDone(F->timeout_data);
76f87348 443 F->timeout_handler = NULL;
a3fa14bf 444 F->timeout = 0;
445 return F->timeout;
5c5783a2 446 }
76f87348 447 assert(handler || F->timeout_handler);
5c5783a2 448 if (handler || data) {
a3fa14bf 449 /* new timeout handler installed. If NULL then the timeout
450 * is only extended
451 */
452 cbdataReferenceDone(F->timeout_data);
76f87348 453 F->timeout_handler = handler;
fa80a8ef 454 F->timeout_data = cbdataReference(data);
30a4f2a8 455 }
a3fa14bf 456 F->timeout = squid_curtime + (time_t) timeout;
457 return F->timeout;
090089c4 458}
459
b8d8561b 460int
0ee4272b 461comm_connect_addr(int sock, const struct sockaddr_in *address)
090089c4 462{
463 int status = COMM_OK;
76f87348 464 fde *F = &fd_table[sock];
090089c4 465 int x;
b5568a61 466 int err = 0;
9689d97c 467 socklen_t errlen;
489b22c1 468 assert(ntohs(address->sin_port) != 0);
090089c4 469 /* Establish connection. */
b5568a61 470 errno = 0;
471 if (!F->flags.called_connect) {
472 F->flags.called_connect = 1;
83704487 473 statCounter.syscalls.sock.connects++;
b5568a61 474 x = connect(sock, (struct sockaddr *) address, sizeof(*address));
54f742e7 475 if (x < 0)
476 debug(5, 9) ("connect FD %d: %s\n", sock, xstrerror());
b5568a61 477 } else {
140e2c0b 478#if defined(_SQUID_NEWSOS6_)
33ac9442 479 /* Makoto MATSUSHITA <matusita@ics.es.osaka-u.ac.jp> */
480 connect(sock, (struct sockaddr *) address, sizeof(*address));
481 if (errno == EINVAL) {
482 errlen = sizeof(err);
483 x = getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &errlen);
484 if (x >= 0)
485 errno = x;
486 }
487#else
b5568a61 488 errlen = sizeof(err);
489 x = getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &errlen);
490 if (x == 0)
491 errno = err;
492#if defined(_SQUID_SOLARIS_)
493 /*
494 * Solaris 2.4's socket emulation doesn't allow you
495 * to determine the error from a failed non-blocking
496 * connect and just returns EPIPE. Create a fake
497 * error message for connect. -- fenner@parc.xerox.com
498 */
499 if (x < 0 && errno == EPIPE)
500 errno = ENOTCONN;
33ac9442 501#endif
30a4f2a8 502#endif
e5f6c5c2 503 }
b5568a61 504 if (errno == 0 || errno == EISCONN)
505 status = COMM_OK;
506 else if (ignoreErrno(errno))
507 status = COMM_INPROGRESS;
508 else
509 return COMM_ERROR;
76f87348 510 xstrncpy(F->ipaddr, inet_ntoa(address->sin_addr), 16);
511 F->remote_port = ntohs(address->sin_port);
090089c4 512 if (status == COMM_OK) {
a3d5953d 513 debug(5, 10) ("comm_connect_addr: FD %d connected to %s:%d\n",
76f87348 514 sock, F->ipaddr, F->remote_port);
f21cd581 515 } else if (status == COMM_INPROGRESS) {
a3d5953d 516 debug(5, 10) ("comm_connect_addr: FD %d connection pending\n", sock);
090089c4 517 }
090089c4 518 return status;
519}
520
521/* Wait for an incoming connection on FD. FD should be a socket returned
522 * from comm_listen. */
b8d8561b 523int
9ef28b60 524comm_accept(int fd, struct sockaddr_in *pn, struct sockaddr_in *me)
090089c4 525{
526 int sock;
1f9afe33 527 struct sockaddr_in P;
528 struct sockaddr_in M;
6637e3a5 529 socklen_t Slen;
76f87348 530 fde *F = NULL;
1f9afe33 531 Slen = sizeof(P);
83704487 532 statCounter.syscalls.sock.accepts++;
603500e7 533 if ((sock = accept(fd, (struct sockaddr *) &P, &Slen)) < 0) {
534 if (ignoreErrno(errno)) {
535 debug(50, 5) ("comm_accept: FD %d: %s\n", fd, xstrerror());
0a0bf5db 536 return COMM_NOMESSAGE;
603500e7 537 } else if (ENFILE == errno || EMFILE == errno) {
538 debug(50, 3) ("comm_accept: FD %d: %s\n", fd, xstrerror());
090089c4 539 return COMM_ERROR;
603500e7 540 } else {
541 debug(50, 1) ("comm_accept: FD %d: %s\n", fd, xstrerror());
090089c4 542 return COMM_ERROR;
543 }
544 }
9ef28b60 545 if (pn)
546 *pn = P;
4053a845 547 Slen = sizeof(M);
548 memset(&M, '\0', Slen);
549 getsockname(sock, (struct sockaddr *) &M, &Slen);
550 if (me)
1f9afe33 551 *me = M;
3ca60c86 552 commSetCloseOnExec(sock);
090089c4 553 /* fdstat update */
5c5783a2 554 fd_open(sock, FD_SOCKET, "HTTP Request");
76f87348 555 F = &fd_table[sock];
c0dec081 556 xstrncpy(F->ipaddr, inet_ntoa(P.sin_addr), 16);
76f87348 557 F->remote_port = htons(P.sin_port);
558 F->local_port = htons(M.sin_port);
090089c4 559 commSetNonBlocking(sock);
090089c4 560 return sock;
561}
562
cb201b7e 563void
564commCallCloseHandlers(int fd)
565{
76f87348 566 fde *F = &fd_table[fd];
f1dc9b30 567 close_handler *ch;
a3d5953d 568 debug(5, 5) ("commCallCloseHandlers: FD %d\n", fd);
76f87348 569 while ((ch = F->close_handler) != NULL) {
570 F->close_handler = ch->next;
9daca08e 571 debug(5, 5) ("commCallCloseHandlers: ch->handler=%p\n", ch->handler);
fa80a8ef 572 if (cbdataReferenceValid(ch->data))
603a02fd 573 ch->handler(fd, ch->data);
fa80a8ef 574 cbdataReferenceDone(ch->data);
7f6ffd15 575 memPoolFree(conn_close_pool, ch); /* AAA */
cb201b7e 576 }
577}
578
5492ad1d 579#if LINGERING_CLOSE
580static void
581commLingerClose(int fd, void *unused)
582{
583 LOCAL_ARRAY(char, buf, 1024);
584 int n;
1f7c9178 585 n = FD_READ_METHOD(fd, buf, 1024);
5492ad1d 586 if (n < 0)
587 debug(5, 3) ("commLingerClose: FD %d read: %s\n", fd, xstrerror());
588 comm_close(fd);
589}
590
591static void
592commLingerTimeout(int fd, void *unused)
593{
594 debug(5, 3) ("commLingerTimeout: FD %d\n", fd);
595 comm_close(fd);
596}
597
598/*
599 * Inspired by apache
600 */
601void
602comm_lingering_close(int fd)
603{
d4c19b39 604#if USE_SSL
605 if (fd_table[fd].ssl)
79d4ccdf 606 ssl_shutdown_method(fd);
d4c19b39 607#endif
5492ad1d 608 if (shutdown(fd, 1) < 0) {
609 comm_close(fd);
610 return;
611 }
612 fd_note(fd, "lingering close");
613 commSetTimeout(fd, 10, commLingerTimeout, NULL);
614 commSetSelect(fd, COMM_SELECT_READ, commLingerClose, NULL, 0);
615}
616#endif
617
98264874 618/*
619 * enable linger with time of 0 so that when the socket is
620 * closed, TCP generates a RESET
621 */
622void
623comm_reset_close(int fd)
624{
625 struct linger L;
626 L.l_onoff = 1;
627 L.l_linger = 0;
628 if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &L, sizeof(L)) < 0)
629 debug(50, 0) ("commResetTCPClose: FD %d: %s\n", fd, xstrerror());
630 comm_close(fd);
631}
632
b8d8561b 633void
634comm_close(int fd)
090089c4 635{
76f87348 636 fde *F = NULL;
1f7c9178 637
a3d5953d 638 debug(5, 5) ("comm_close: FD %d\n", fd);
03eb2f01 639 assert(fd >= 0);
640 assert(fd < Squid_MaxFD);
76f87348 641 F = &fd_table[fd];
1f7c9178 642
58a6c186 643 if (F->flags.closing)
e102ebda 644 return;
60c0b5a2 645 if (shutting_down && (!F->flags.open || F->type == FD_FILE))
6cf028ab 646 return;
60c0b5a2 647 assert(F->flags.open);
76f87348 648 assert(F->type != FD_FILE);
58a6c186 649 F->flags.closing = 1;
d4c19b39 650#if USE_SSL
651 if (F->ssl)
79d4ccdf 652 ssl_shutdown_method(fd);
d4c19b39 653#endif
fa80a8ef 654 commSetTimeout(fd, -1, NULL, NULL);
96f1be5d 655 CommWriteStateCallbackAndFree(fd, COMM_ERR_CLOSING);
cb201b7e 656 commCallCloseHandlers(fd);
b716a8ad 657 if (F->uses) /* assume persistent connect count */
658 pconnHistCount(1, F->uses);
d4c19b39 659#if USE_SSL
660 if (F->ssl) {
661 SSL_free(F->ssl);
662 F->ssl = NULL;
663 }
664#endif
5c5783a2 665 fd_close(fd); /* update fdstat */
5874bf28 666 close(fd);
83704487 667 statCounter.syscalls.sock.closes++;
090089c4 668}
669
090089c4 670/* Send a udp datagram to specified TO_ADDR. */
b8d8561b 671int
5df61230 672comm_udp_sendto(int fd,
673 const struct sockaddr_in *to_addr,
674 int addr_len,
17b6e784 675 const void *buf,
5df61230 676 int len)
090089c4 677{
5df61230 678 int x;
83704487 679 statCounter.syscalls.sock.sendtos++;
5df61230 680 x = sendto(fd, buf, len, 0, (struct sockaddr *) to_addr, addr_len);
681 if (x < 0) {
17d51783 682#ifdef _SQUID_LINUX_
683 if (ECONNREFUSED != errno)
684#endif
685 debug(50, 1) ("comm_udp_sendto: FD %d, %s, port %d: %s\n",
686 fd,
687 inet_ntoa(to_addr->sin_addr),
688 (int) htons(to_addr->sin_port),
689 xstrerror());
090089c4 690 return COMM_ERROR;
691 }
5df61230 692 return x;
090089c4 693}
694
b8d8561b 695void
70a9dab4 696commSetDefer(int fd, DEFER * func, void *data)
4883993a 697{
da2b3a17 698 fde *F = &fd_table[fd];
699 F->defer_check = func;
70a9dab4 700 F->defer_data = data;
4883993a 701}
702
b8d8561b 703void
582b6456 704comm_add_close_handler(int fd, PF * handler, void *data)
30a4f2a8 705{
7f6ffd15 706 close_handler *new = memPoolAlloc(conn_close_pool); /* AAA */
cddc721b 707 close_handler *c;
a3d5953d 708 debug(5, 5) ("comm_add_close_handler: FD %d, handler=%p, data=%p\n",
e0c42e90 709 fd, handler, data);
6a988308 710 for (c = fd_table[fd].close_handler; c; c = c->next)
aeca2a09 711 assert(c->handler != handler || c->data != data);
30a4f2a8 712 new->handler = handler;
fa80a8ef 713 new->data = cbdataReference(data);
30a4f2a8 714 new->next = fd_table[fd].close_handler;
715 fd_table[fd].close_handler = new;
716}
717
b8d8561b 718void
582b6456 719comm_remove_close_handler(int fd, PF * handler, void *data)
090089c4 720{
f1dc9b30 721 close_handler *p;
722 close_handler *last = NULL;
30a4f2a8 723 /* Find handler in list */
e869f2bd 724 debug(5, 5) ("comm_remove_close_handler: FD %d, handler=%p, data=%p\n",
725 fd, handler, data);
30a4f2a8 726 for (p = fd_table[fd].close_handler; p != NULL; last = p, p = p->next)
727 if (p->handler == handler && p->data == data)
728 break; /* This is our handler */
f88211e8 729 assert(p != NULL);
30a4f2a8 730 /* Remove list entry */
731 if (last)
732 last->next = p->next;
733 else
734 fd_table[fd].close_handler = p->next;
fa80a8ef 735 cbdataReferenceDone(p->data);
736 memPoolFree(conn_close_pool, p);
30a4f2a8 737}
090089c4 738
b8d8561b 739static void
740commSetNoLinger(int fd)
30a4f2a8 741{
742 struct linger L;
090089c4 743 L.l_onoff = 0; /* off */
744 L.l_linger = 0;
30a4f2a8 745 if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &L, sizeof(L)) < 0)
a3d5953d 746 debug(50, 0) ("commSetNoLinger: FD %d: %s\n", fd, xstrerror());
58a6c186 747 fd_table[fd].flags.nolinger = 1;
090089c4 748}
749
b8d8561b 750static void
751commSetReuseAddr(int fd)
090089c4 752{
753 int on = 1;
30a4f2a8 754 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0)
a3d5953d 755 debug(50, 1) ("commSetReuseAddr: FD %d: %s\n", fd, xstrerror());
090089c4 756}
757
b8d8561b 758static void
759commSetTcpRcvbuf(int fd, int size)
f868539a 760{
761 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *) &size, sizeof(size)) < 0)
a3d5953d 762 debug(50, 1) ("commSetTcpRcvbuf: FD %d, SIZE %d: %s\n",
b6f794d6 763 fd, size, xstrerror());
f868539a 764}
765
b8d8561b 766int
767commSetNonBlocking(int fd)
30a4f2a8 768{
731e4d49 769 int flags;
9e205701 770 int dummy = 0;
7f6ffd15 771#ifdef _SQUID_CYGWIN_
b05490a8 772 int nonblocking = TRUE;
7f6ffd15 773 if (fd_table[fd].type != FD_PIPE) {
774 if (ioctl(fd, FIONBIO, &nonblocking) < 0) {
775 debug(50, 0) ("commSetNonBlocking: FD %d: %s %D\n", fd, xstrerror(), fd_table[fd].type);
776 return COMM_ERROR;
777 }
778 } else {
779#endif
780 if ((flags = fcntl(fd, F_GETFL, dummy)) < 0) {
781 debug(50, 0) ("FD %d: fcntl F_GETFL: %s\n", fd, xstrerror());
782 return COMM_ERROR;
783 }
784 if (fcntl(fd, F_SETFL, flags | SQUID_NONBLOCK) < 0) {
785 debug(50, 0) ("commSetNonBlocking: FD %d: %s\n", fd, xstrerror());
786 return COMM_ERROR;
787 }
788#ifdef _SQUID_CYGWIN_
090089c4 789 }
7f6ffd15 790#endif
58a6c186 791 fd_table[fd].flags.nonblocking = 1;
090089c4 792 return 0;
793}
794
7e3ce7b9 795int
796commUnsetNonBlocking(int fd)
797{
798 int flags;
799 int dummy = 0;
800 if ((flags = fcntl(fd, F_GETFL, dummy)) < 0) {
801 debug(50, 0) ("FD %d: fcntl F_GETFL: %s\n", fd, xstrerror());
802 return COMM_ERROR;
803 }
804 if (fcntl(fd, F_SETFL, flags & (~SQUID_NONBLOCK)) < 0) {
805 debug(50, 0) ("commUnsetNonBlocking: FD %d: %s\n", fd, xstrerror());
806 return COMM_ERROR;
807 }
808 fd_table[fd].flags.nonblocking = 0;
809 return 0;
810}
811
b8d8561b 812void
813commSetCloseOnExec(int fd)
3ca60c86 814{
815#ifdef FD_CLOEXEC
731e4d49 816 int flags;
7a18b487 817 int dummy = 0;
c7989865 818 if ((flags = fcntl(fd, F_GETFL, dummy)) < 0) {
a3d5953d 819 debug(50, 0) ("FD %d: fcntl F_GETFL: %s\n", fd, xstrerror());
24382924 820 return;
3ca60c86 821 }
24382924 822 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
a3d5953d 823 debug(50, 0) ("FD %d: set close-on-exec failed: %s\n", fd, xstrerror());
d6827718 824 fd_table[fd].flags.close_on_exec = 1;
3ca60c86 825#endif
826}
827
e90100aa 828#ifdef TCP_NODELAY
829static void
830commSetTcpNoDelay(int fd)
831{
832 int on = 1;
833 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on)) < 0)
a3d5953d 834 debug(50, 1) ("commSetTcpNoDelay: FD %d: %s\n", fd, xstrerror());
d6827718 835 fd_table[fd].flags.nodelay = 1;
e90100aa 836}
837#endif
838
6a988308 839
d86b3703 840void
0673c0ba 841comm_init(void)
090089c4 842{
f1dc9b30 843 fd_table = xcalloc(Squid_MaxFD, sizeof(fde));
59c4d35b 844 /* XXX account fd_table */
090089c4 845 /* Keep a few file descriptors free so that we don't run out of FD's
846 * after accepting a client but before it opens a socket or a file.
e83892e9 847 * Since Squid_MaxFD can be as high as several thousand, don't waste them */
0254ee29 848 RESERVED_FD = XMIN(100, Squid_MaxFD / 4);
28c60158 849 CBDATA_INIT_TYPE(ConnectStateData);
723123a9 850 comm_write_pool = memPoolCreate("CommWriteStateData", sizeof(CommWriteStateData));
58cd5bbd 851 conn_close_pool = memPoolCreate("close_handler", sizeof(close_handler));
090089c4 852}
853
30a4f2a8 854/* Write to FD. */
b8d8561b 855static void
582b6456 856commHandleWrite(int fd, void *data)
30a4f2a8 857{
f17936ab 858 CommWriteStateData *state = data;
30a4f2a8 859 int len = 0;
860 int nleft;
861
32754419 862 debug(5, 5) ("commHandleWrite: FD %d: off %ld, sz %ld.\n",
863 fd, (long int) state->offset, (long int) state->size);
30a4f2a8 864
865 nleft = state->size - state->offset;
1f7c9178 866 len = FD_WRITE_METHOD(fd, state->buf + state->offset, nleft);
6a988308 867 debug(5, 5) ("commHandleWrite: write() returns %d\n", len);
b69f7771 868 fd_bytes(fd, len, FD_WRITE);
83704487 869 statCounter.syscalls.sock.writes++;
30a4f2a8 870
871 if (len == 0) {
872 /* Note we even call write if nleft == 0 */
873 /* We're done */
874 if (nleft != 0)
02be0294 875 debug(5, 1) ("commHandleWrite: FD %d: write failure: connection closed with %d bytes remaining.\n", fd, nleft);
f17936ab 876 CommWriteStateCallbackAndFree(fd, nleft ? COMM_ERROR : COMM_OK);
30a4f2a8 877 } else if (len < 0) {
878 /* An error */
e8d6569c 879 if (fd_table[fd].flags.socket_eof) {
880 debug(50, 2) ("commHandleWrite: FD %d: write failure: %s.\n",
881 fd, xstrerror());
882 CommWriteStateCallbackAndFree(fd, COMM_ERROR);
883 } else if (ignoreErrno(errno)) {
a3d5953d 884 debug(50, 10) ("commHandleWrite: FD %d: write failure: %s.\n",
30a4f2a8 885 fd, xstrerror());
b177367b 886 commSetSelect(fd,
30a4f2a8 887 COMM_SELECT_WRITE,
cd1fb0eb 888 commHandleWrite,
b177367b 889 state,
85d7ea98 890 0);
9864ee44 891 } else {
a3d5953d 892 debug(50, 2) ("commHandleWrite: FD %d: write failure: %s.\n",
9864ee44 893 fd, xstrerror());
f17936ab 894 CommWriteStateCallbackAndFree(fd, COMM_ERROR);
30a4f2a8 895 }
30a4f2a8 896 } else {
897 /* A successful write, continue */
898 state->offset += len;
899 if (state->offset < state->size) {
900 /* Not done, reinstall the write handler and write some more */
b177367b 901 commSetSelect(fd,
30a4f2a8 902 COMM_SELECT_WRITE,
cd1fb0eb 903 commHandleWrite,
b177367b 904 state,
85d7ea98 905 0);
9864ee44 906 } else {
f17936ab 907 CommWriteStateCallbackAndFree(fd, COMM_OK);
30a4f2a8 908 }
30a4f2a8 909 }
910}
911
912
913
914/* Select for Writing on FD, until SIZE bytes are sent. Call
a695e7ee 915 * *HANDLER when complete. */
b8d8561b 916void
a2c963ae 917comm_write(int fd, const char *buf, int size, CWCB * handler, void *handler_data, FREE * free_func)
30a4f2a8 918{
aa9e2cab 919 CommWriteStateData *state = fd_table[fd].rwstate;
a3d5953d 920 debug(5, 5) ("comm_write: FD %d: sz %d: hndl %p: data %p.\n",
787869c5 921 fd, size, handler, handler_data);
aa9e2cab 922 if (NULL != state) {
afde8a9d 923 debug(5, 1) ("comm_write: fd_table[%d].rwstate != NULL\n", fd);
723123a9 924 memPoolFree(comm_write_pool, state);
6cf028ab 925 fd_table[fd].rwstate = NULL;
926 }
723123a9 927 fd_table[fd].rwstate = state = memPoolAlloc(comm_write_pool);
a2c963ae 928 state->buf = (char *) buf;
30a4f2a8 929 state->size = size;
930 state->offset = 0;
931 state->handler = handler;
fa80a8ef 932 state->handler_data = cbdataReference(handler_data);
c0dec081 933 state->free_func = free_func;
aa9e2cab 934 commSetSelect(fd, COMM_SELECT_WRITE, commHandleWrite, state, 0);
30a4f2a8 935}
26a880e2 936
137ee196 937/* a wrapper around comm_write to allow for MemBuf to be comm_written in a snap */
cb69b4c7 938void
939comm_write_mbuf(int fd, MemBuf mb, CWCB * handler, void *handler_data)
940{
941 comm_write(fd, mb.buf, mb.size, handler, handler_data, memBufFreeFunc(&mb));
942}
943
89924214 944/*
945 * hm, this might be too general-purpose for all the places we'd
946 * like to use it.
947 */
b224ea98 948int
edd2eb63 949ignoreErrno(int ierrno)
26a880e2 950{
603500e7 951 switch (ierrno) {
89924214 952 case EINPROGRESS:
603500e7 953 case EWOULDBLOCK:
26a880e2 954#if EAGAIN != EWOULDBLOCK
603500e7 955 case EAGAIN:
26a880e2 956#endif
603500e7 957 case EALREADY:
958 case EINTR:
db494ab8 959#ifdef ERESTART
960 case ERESTART:
961#endif
26a880e2 962 return 1;
603500e7 963 default:
964 return 0;
965 }
966 /* NOTREACHED */
26a880e2 967}
d723bf6b 968
969void
970commCloseAllSockets(void)
971{
972 int fd;
973 fde *F = NULL;
d723bf6b 974 for (fd = 0; fd <= Biggest_FD; fd++) {
975 F = &fd_table[fd];
60c0b5a2 976 if (!F->flags.open)
d723bf6b 977 continue;
978 if (F->type != FD_SOCKET)
979 continue;
de718ec4 980 if (F->flags.ipc) /* don't close inter-process sockets */
981 continue;
d723bf6b 982 if (F->timeout_handler) {
fa80a8ef 983 PF *callback = F->timeout_handler;
984 void *cbdata = NULL;
985 F->timeout_handler = NULL;
d723bf6b 986 debug(5, 5) ("commCloseAllSockets: FD %d: Calling timeout handler\n",
987 fd);
fa80a8ef 988 if (cbdataReferenceValidDone(F->timeout_data, &cbdata))
989 callback(fd, cbdata);
d723bf6b 990 } else {
991 debug(5, 5) ("commCloseAllSockets: FD %d: calling comm_close()\n", fd);
992 comm_close(fd);
993 }
994 }
995}
1b3db6d9 996
997void
998checkTimeouts(void)
999{
1000 int fd;
1001 fde *F = NULL;
1002 PF *callback;
1003 for (fd = 0; fd <= Biggest_FD; fd++) {
b5443c04 1004 F = &fd_table[fd];
1005 if (!F->flags.open)
1006 continue;
1007 if (F->timeout == 0)
1008 continue;
1009 if (F->timeout > squid_curtime)
1010 continue;
1011 debug(5, 5) ("checkTimeouts: FD %d Expired\n", fd);
1012 if (F->timeout_handler) {
1013 debug(5, 5) ("checkTimeouts: FD %d: Call timeout handler\n", fd);
1014 callback = F->timeout_handler;
1015 F->timeout_handler = NULL;
1016 callback(fd, F->timeout_data);
1017 } else {
1018 debug(5, 5) ("checkTimeouts: FD %d: Forcing comm_close()\n", fd);
1019 comm_close(fd);
1020 }
1021 }
1022}
1023
1024
1025int
1b3db6d9 1026commDeferRead(int fd)
1027{
1028 fde *F = &fd_table[fd];
1029 if (F->defer_check == NULL)
b5443c04 1030 return 0;
1b3db6d9 1031 return F->defer_check(fd, F->defer_data);
1032}