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