]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/comm.cc
3 * $Id: comm.cc,v 1.315 2001/01/12 00:37:16 wessels Exp $
5 * DEBUG: section 5 Socket Functions
6 * AUTHOR: Harvest Derived
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
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.
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.
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.
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
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
38 #ifdef HAVE_NETINET_TCP_H
39 #include <netinet/tcp.h>
48 struct in_addr in_addr
;
57 static int commBind(int s
, struct in_addr
, u_short port
);
58 static void commSetReuseAddr(int);
59 static void commSetNoLinger(int);
60 static void CommWriteStateCallbackAndFree(int fd
, int code
);
62 static void commSetTcpNoDelay(int);
64 static void commSetTcpRcvbuf(int, int);
65 static PF commConnectFree
;
66 static PF commConnectHandle
;
67 static PF commHandleWrite
;
68 static IPH commConnectDnsHandle
;
69 static void commConnectCallback(ConnectStateData
* cs
, int status
);
70 static int commResetFD(ConnectStateData
* cs
);
71 static int commRetryConnect(ConnectStateData
* cs
);
72 CBDATA_TYPE(ConnectStateData
);
74 static MemPool
*comm_write_pool
= NULL
;
75 static MemPool
*conn_close_pool
= NULL
;
78 CommWriteStateCallbackAndFree(int fd
, int code
)
80 CommWriteStateData
*CommWriteState
= fd_table
[fd
].rwstate
;
81 CWCB
*callback
= NULL
;
83 fd_table
[fd
].rwstate
= NULL
;
84 if (CommWriteState
== NULL
)
86 if (CommWriteState
->free_func
) {
87 FREE
*free_func
= CommWriteState
->free_func
;
88 void *free_buf
= CommWriteState
->buf
;
89 CommWriteState
->free_func
= NULL
;
90 CommWriteState
->buf
= NULL
;
93 callback
= CommWriteState
->handler
;
94 data
= CommWriteState
->handler_data
;
95 CommWriteState
->handler
= NULL
;
96 if (callback
&& cbdataValid(data
))
97 callback(fd
, CommWriteState
->buf
, CommWriteState
->offset
, code
, data
);
99 memPoolFree(comm_write_pool
, CommWriteState
);
102 /* Return the local port associated with fd. */
104 comm_local_port(int fd
)
106 struct sockaddr_in addr
;
107 socklen_t addr_len
= 0;
108 fde
*F
= &fd_table
[fd
];
110 /* If the fd is closed already, just return */
111 if (!F
->flags
.open
) {
112 debug(5, 0) ("comm_local_port: FD %d has been closed.\n", fd
);
116 return F
->local_port
;
117 addr_len
= sizeof(addr
);
118 if (getsockname(fd
, (struct sockaddr
*) &addr
, &addr_len
)) {
119 debug(50, 1) ("comm_local_port: Failed to retrieve TCP/UDP port number for socket: FD %d: %s\n", fd
, xstrerror());
122 F
->local_port
= ntohs(addr
.sin_port
);
123 debug(5, 6) ("comm_local_port: FD %d: port %d\n", fd
, (int) F
->local_port
);
124 return F
->local_port
;
128 commBind(int s
, struct in_addr in_addr
, u_short port
)
130 struct sockaddr_in S
;
132 memset(&S
, '\0', sizeof(S
));
133 S
.sin_family
= AF_INET
;
134 S
.sin_port
= htons(port
);
135 S
.sin_addr
= in_addr
;
136 statCounter
.syscalls
.sock
.binds
++;
137 if (bind(s
, (struct sockaddr
*) &S
, sizeof(S
)) == 0)
139 debug(50, 0) ("commBind: Cannot bind socket FD %d to %s:%d: %s\n",
141 S
.sin_addr
.s_addr
== INADDR_ANY
? "*" : inet_ntoa(S
.sin_addr
),
147 /* Create a socket. Default is blocking, stream (TCP) socket. IO_TYPE
148 * is OR of flags specified in comm.h. */
150 comm_open(int sock_type
,
160 /* Create socket for accepting new connections. */
161 statCounter
.syscalls
.sock
.sockets
++;
162 if ((new_socket
= socket(AF_INET
, sock_type
, proto
)) < 0) {
163 /* Increase the number of reserved fd's if calls to socket()
164 * are failing because the open file table is full. This
165 * limits the number of simultaneous clients */
169 debug(50, 1) ("comm_open: socket failure: %s\n", xstrerror());
173 debug(50, 0) ("comm_open: socket failure: %s\n", xstrerror());
178 debug(5, 5) ("comm_open: FD %d is a new socket\n", new_socket
);
179 fd_open(new_socket
, FD_SOCKET
, note
);
180 F
= &fd_table
[new_socket
];
181 if (!(flags
& COMM_NOCLOEXEC
))
182 commSetCloseOnExec(new_socket
);
183 if ((flags
& COMM_REUSEADDR
))
184 commSetReuseAddr(new_socket
);
185 if (port
> (u_short
) 0) {
186 commSetNoLinger(new_socket
);
188 commSetReuseAddr(new_socket
);
190 if (addr
.s_addr
!= no_addr
.s_addr
) {
191 if (commBind(new_socket
, addr
, port
) != COMM_OK
) {
192 comm_close(new_socket
);
196 F
->local_port
= port
;
198 if (flags
& COMM_NONBLOCKING
)
199 if (commSetNonBlocking(new_socket
) == COMM_ERROR
)
202 if (sock_type
== SOCK_STREAM
)
203 commSetTcpNoDelay(new_socket
);
205 if (Config
.tcpRcvBufsz
> 0 && sock_type
== SOCK_STREAM
)
206 commSetTcpRcvbuf(new_socket
, Config
.tcpRcvBufsz
);
211 * NOTE: set the listen queue to Squid_MaxFD/4 and rely on the kernel to
212 * impose an upper limit. Solaris' listen(3n) page says it has
213 * no limit on this parameter, but sys/socket.h sets SOMAXCONN
214 * to 5. HP-UX currently has a limit of 20. SunOS is 5 and
218 comm_listen(int sock
)
221 if ((x
= listen(sock
, Squid_MaxFD
>> 2)) < 0) {
222 debug(50, 0) ("comm_listen: listen(%d, %d): %s\n",
231 commConnectStart(int fd
, const char *host
, u_short port
, CNCB
* callback
, void *data
)
233 ConnectStateData
*cs
;
234 debug(5, 3) ("commConnectStart: FD %d, %s:%d\n", fd
, host
, (int) port
);
235 cs
= CBDATA_ALLOC(ConnectStateData
, NULL
);
237 cs
->host
= xstrdup(host
);
239 cs
->callback
= callback
;
241 cbdataLock(cs
->data
);
242 comm_add_close_handler(fd
, commConnectFree
, cs
);
244 ipcache_nbgethostbyname(host
, commConnectDnsHandle
, cs
);
248 commConnectDnsHandle(const ipcache_addrs
* ia
, void *data
)
250 ConnectStateData
*cs
= data
;
251 assert(cs
->locks
== 1);
254 debug(5, 3) ("commConnectDnsHandle: Unknown host: %s\n", cs
->host
);
255 if (!dns_error_message
) {
256 dns_error_message
= "Unknown DNS error";
257 debug(5, 1) ("commConnectDnsHandle: Bad dns_error_message\n");
259 assert(dns_error_message
!= NULL
);
260 commConnectCallback(cs
, COMM_ERR_DNS
);
263 assert(ia
->cur
< ia
->count
);
264 cs
->in_addr
= ia
->in_addrs
[ia
->cur
];
265 ipcacheCycleAddr(cs
->host
, NULL
);
266 cs
->addrcount
= ia
->count
;
267 cs
->connstart
= squid_curtime
;
268 commConnectHandle(cs
->fd
, cs
);
272 commConnectCallback(ConnectStateData
* cs
, int status
)
274 CNCB
*callback
= cs
->callback
;
275 void *data
= cs
->data
;
277 comm_remove_close_handler(fd
, commConnectFree
, cs
);
280 commSetTimeout(fd
, -1, NULL
, NULL
);
281 commConnectFree(fd
, cs
);
282 if (cbdataValid(data
))
283 callback(fd
, status
, data
);
288 commConnectFree(int fd
, void *data
)
290 ConnectStateData
*cs
= data
;
291 debug(5, 3) ("commConnectFree: FD %d\n", fd
);
293 cbdataUnlock(cs
->data
);
298 /* Reset FD so that we can connect() again */
300 commResetFD(ConnectStateData
* cs
)
303 if (!cbdataValid(cs
->data
))
305 statCounter
.syscalls
.sock
.sockets
++;
306 fd2
= socket(AF_INET
, SOCK_STREAM
, 0);
307 statCounter
.syscalls
.sock
.sockets
++;
309 debug(5, 0) ("commResetFD: socket: %s\n", xstrerror());
310 if (ENFILE
== errno
|| EMFILE
== errno
)
314 if (dup2(fd2
, cs
->fd
) < 0) {
315 debug(5, 0) ("commResetFD: dup2: %s\n", xstrerror());
316 if (ENFILE
== errno
|| EMFILE
== errno
)
321 fd_table
[cs
->fd
].flags
.called_connect
= 0;
323 * yuck, this has assumptions about comm_open() arguments for
324 * the original socket
326 commSetCloseOnExec(cs
->fd
);
327 if (Config
.Addrs
.tcp_outgoing
.s_addr
!= no_addr
.s_addr
) {
328 if (commBind(cs
->fd
, Config
.Addrs
.tcp_outgoing
, 0) != COMM_OK
) {
332 commSetNonBlocking(cs
->fd
);
334 commSetTcpNoDelay(cs
->fd
);
336 if (Config
.tcpRcvBufsz
> 0)
337 commSetTcpRcvbuf(cs
->fd
, Config
.tcpRcvBufsz
);
342 commRetryConnect(ConnectStateData
* cs
)
344 assert(cs
->addrcount
> 0);
345 if (cs
->addrcount
== 1) {
346 if (cs
->tries
>= Config
.retry
.maxtries
)
348 if (squid_curtime
- cs
->connstart
> Config
.Timeout
.connect
)
351 if (cs
->tries
> cs
->addrcount
)
354 return commResetFD(cs
);
357 /* Connect SOCK to specified DEST_PORT at DEST_HOST. */
359 commConnectHandle(int fd
, void *data
)
361 ConnectStateData
*cs
= data
;
362 if (cs
->S
.sin_addr
.s_addr
== 0) {
363 cs
->S
.sin_family
= AF_INET
;
364 cs
->S
.sin_addr
= cs
->in_addr
;
365 cs
->S
.sin_port
= htons(cs
->port
);
366 if (Config
.onoff
.log_fqdn
)
367 fqdncache_gethostbyaddr(cs
->S
.sin_addr
, FQDN_LOOKUP_IF_MISS
);
369 switch (comm_connect_addr(fd
, &cs
->S
)) {
370 case COMM_INPROGRESS
:
371 debug(5, 5) ("commConnectHandle: FD %d: COMM_INPROGRESS\n", fd
);
372 commSetSelect(fd
, COMM_SELECT_WRITE
, commConnectHandle
, cs
, 0);
375 ipcacheMarkGoodAddr(cs
->host
, cs
->S
.sin_addr
);
376 commConnectCallback(cs
, COMM_OK
);
380 ipcacheMarkBadAddr(cs
->host
, cs
->S
.sin_addr
);
381 if (Config
.onoff
.test_reachability
)
382 netdbDeleteAddrNetwork(cs
->S
.sin_addr
);
383 if (commRetryConnect(cs
)) {
385 ipcache_nbgethostbyname(cs
->host
, commConnectDnsHandle
, cs
);
387 commConnectCallback(cs
, COMM_ERR_CONNECT
);
394 commSetTimeout(int fd
, int timeout
, PF
* handler
, void *data
)
397 debug(5, 3) ("commSetTimeout: FD %d timeout %d\n", fd
, timeout
);
399 assert(fd
< Squid_MaxFD
);
401 assert(F
->flags
.open
);
403 F
->timeout_handler
= NULL
;
404 F
->timeout_data
= NULL
;
405 return F
->timeout
= 0;
407 assert(handler
|| F
->timeout_handler
);
408 if (handler
|| data
) {
409 F
->timeout_handler
= handler
;
410 F
->timeout_data
= data
;
412 return F
->timeout
= squid_curtime
+ (time_t) timeout
;
416 comm_connect_addr(int sock
, const struct sockaddr_in
*address
)
418 int status
= COMM_OK
;
419 fde
*F
= &fd_table
[sock
];
423 assert(ntohs(address
->sin_port
) != 0);
424 /* Establish connection. */
426 if (!F
->flags
.called_connect
) {
427 F
->flags
.called_connect
= 1;
428 statCounter
.syscalls
.sock
.connects
++;
429 x
= connect(sock
, (struct sockaddr
*) address
, sizeof(*address
));
431 debug(5, 9) ("connect FD %d: %s\n", sock
, xstrerror());
433 #if defined(_SQUID_NEWSOS6_)
434 /* Makoto MATSUSHITA <matusita@ics.es.osaka-u.ac.jp> */
435 connect(sock
, (struct sockaddr
*) address
, sizeof(*address
));
436 if (errno
== EINVAL
) {
437 errlen
= sizeof(err
);
438 x
= getsockopt(sock
, SOL_SOCKET
, SO_ERROR
, &err
, &errlen
);
443 errlen
= sizeof(err
);
444 x
= getsockopt(sock
, SOL_SOCKET
, SO_ERROR
, &err
, &errlen
);
447 #if defined(_SQUID_SOLARIS_)
449 * Solaris 2.4's socket emulation doesn't allow you
450 * to determine the error from a failed non-blocking
451 * connect and just returns EPIPE. Create a fake
452 * error message for connect. -- fenner@parc.xerox.com
454 if (x
< 0 && errno
== EPIPE
)
459 if (errno
== 0 || errno
== EISCONN
)
461 else if (ignoreErrno(errno
))
462 status
= COMM_INPROGRESS
;
465 xstrncpy(F
->ipaddr
, inet_ntoa(address
->sin_addr
), 16);
466 F
->remote_port
= ntohs(address
->sin_port
);
467 if (status
== COMM_OK
) {
468 debug(5, 10) ("comm_connect_addr: FD %d connected to %s:%d\n",
469 sock
, F
->ipaddr
, F
->remote_port
);
470 } else if (status
== COMM_INPROGRESS
) {
471 debug(5, 10) ("comm_connect_addr: FD %d connection pending\n", sock
);
476 /* Wait for an incoming connection on FD. FD should be a socket returned
477 * from comm_listen. */
479 comm_accept(int fd
, struct sockaddr_in
*pn
, struct sockaddr_in
*me
)
482 struct sockaddr_in P
;
483 struct sockaddr_in M
;
487 statCounter
.syscalls
.sock
.accepts
++;
488 if ((sock
= accept(fd
, (struct sockaddr
*) &P
, &Slen
)) < 0) {
489 if (ignoreErrno(errno
)) {
490 debug(50, 5) ("comm_accept: FD %d: %s\n", fd
, xstrerror());
491 return COMM_NOMESSAGE
;
492 } else if (ENFILE
== errno
|| EMFILE
== errno
) {
493 debug(50, 3) ("comm_accept: FD %d: %s\n", fd
, xstrerror());
496 debug(50, 1) ("comm_accept: FD %d: %s\n", fd
, xstrerror());
503 memset(&M
, '\0', Slen
);
504 getsockname(sock
, (struct sockaddr
*) &M
, &Slen
);
507 commSetCloseOnExec(sock
);
509 fd_open(sock
, FD_SOCKET
, "HTTP Request");
511 xstrncpy(F
->ipaddr
, inet_ntoa(P
.sin_addr
), 16);
512 F
->remote_port
= htons(P
.sin_port
);
513 F
->local_port
= htons(M
.sin_port
);
514 commSetNonBlocking(sock
);
519 commCallCloseHandlers(int fd
)
521 fde
*F
= &fd_table
[fd
];
523 debug(5, 5) ("commCallCloseHandlers: FD %d\n", fd
);
524 while ((ch
= F
->close_handler
) != NULL
) {
525 F
->close_handler
= ch
->next
;
526 debug(5, 5) ("commCallCloseHandlers: ch->handler=%p\n", ch
->handler
);
527 if (cbdataValid(ch
->data
))
528 ch
->handler(fd
, ch
->data
);
529 cbdataUnlock(ch
->data
);
530 memPoolFree(conn_close_pool
, ch
); /* AAA */
536 commLingerClose(int fd
, void *unused
)
538 LOCAL_ARRAY(char, buf
, 1024);
540 n
= read(fd
, buf
, 1024);
542 debug(5, 3) ("commLingerClose: FD %d read: %s\n", fd
, xstrerror());
547 commLingerTimeout(int fd
, void *unused
)
549 debug(5, 3) ("commLingerTimeout: FD %d\n", fd
);
557 comm_lingering_close(int fd
)
559 if (shutdown(fd
, 1) < 0) {
563 fd_note(fd
, "lingering close");
564 commSetTimeout(fd
, 10, commLingerTimeout
, NULL
);
565 commSetSelect(fd
, COMM_SELECT_READ
, commLingerClose
, NULL
, 0);
573 debug(5, 5) ("comm_close: FD %d\n", fd
);
575 assert(fd
< Squid_MaxFD
);
577 if (F
->flags
.closing
)
579 if (shutting_down
&& (!F
->flags
.open
|| F
->type
== FD_FILE
))
581 assert(F
->flags
.open
);
582 assert(F
->type
!= FD_FILE
);
583 F
->flags
.closing
= 1;
584 CommWriteStateCallbackAndFree(fd
, COMM_ERR_CLOSING
);
585 commCallCloseHandlers(fd
);
586 if (F
->uses
) /* assume persistent connect count */
587 pconnHistCount(1, F
->uses
);
588 fd_close(fd
); /* update fdstat */
590 statCounter
.syscalls
.sock
.closes
++;
593 /* Send a udp datagram to specified TO_ADDR. */
595 comm_udp_sendto(int fd
,
596 const struct sockaddr_in
*to_addr
,
602 statCounter
.syscalls
.sock
.sendtos
++;
603 x
= sendto(fd
, buf
, len
, 0, (struct sockaddr
*) to_addr
, addr_len
);
606 if (ECONNREFUSED
!= errno
)
608 debug(50, 1) ("comm_udp_sendto: FD %d, %s, port %d: %s\n",
610 inet_ntoa(to_addr
->sin_addr
),
611 (int) htons(to_addr
->sin_port
),
619 commSetDefer(int fd
, DEFER
* func
, void *data
)
621 fde
*F
= &fd_table
[fd
];
622 F
->defer_check
= func
;
623 F
->defer_data
= data
;
627 commSetSelect(int fd
, unsigned int type
, PF
* handler
, void *client_data
, time_t timeout
)
629 fde
*F
= &fd_table
[fd
];
631 assert(F
->flags
.open
);
632 debug(5, 5) ("commSetSelect: FD %d type %d\n", fd
, type
);
633 if (type
& COMM_SELECT_READ
) {
634 F
->read_handler
= handler
;
635 F
->read_data
= client_data
;
636 commUpdateReadBits(fd
, handler
);
638 if (type
& COMM_SELECT_WRITE
) {
639 F
->write_handler
= handler
;
640 F
->write_data
= client_data
;
641 commUpdateWriteBits(fd
, handler
);
644 F
->timeout
= squid_curtime
+ timeout
;
648 comm_add_close_handler(int fd
, PF
* handler
, void *data
)
650 close_handler
*new = memPoolAlloc(conn_close_pool
); /* AAA */
652 debug(5, 5) ("comm_add_close_handler: FD %d, handler=%p, data=%p\n",
654 for (c
= fd_table
[fd
].close_handler
; c
; c
= c
->next
)
655 assert(c
->handler
!= handler
|| c
->data
!= data
);
656 new->handler
= handler
;
658 new->next
= fd_table
[fd
].close_handler
;
659 fd_table
[fd
].close_handler
= new;
664 comm_remove_close_handler(int fd
, PF
* handler
, void *data
)
667 close_handler
*last
= NULL
;
668 /* Find handler in list */
669 debug(5, 5) ("comm_remove_close_handler: FD %d, handler=%p, data=%p\n",
671 for (p
= fd_table
[fd
].close_handler
; p
!= NULL
; last
= p
, p
= p
->next
)
672 if (p
->handler
== handler
&& p
->data
== data
)
673 break; /* This is our handler */
675 /* Remove list entry */
677 last
->next
= p
->next
;
679 fd_table
[fd
].close_handler
= p
->next
;
680 cbdataUnlock(p
->data
);
681 memPoolFree(conn_close_pool
, p
); /* AAA */
686 commSetNoLinger(int fd
)
689 L
.l_onoff
= 0; /* off */
691 if (setsockopt(fd
, SOL_SOCKET
, SO_LINGER
, (char *) &L
, sizeof(L
)) < 0)
692 debug(50, 0) ("commSetNoLinger: FD %d: %s\n", fd
, xstrerror());
693 fd_table
[fd
].flags
.nolinger
= 1;
697 commSetReuseAddr(int fd
)
700 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &on
, sizeof(on
)) < 0)
701 debug(50, 1) ("commSetReuseAddr: FD %d: %s\n", fd
, xstrerror());
705 commSetTcpRcvbuf(int fd
, int size
)
707 if (setsockopt(fd
, SOL_SOCKET
, SO_RCVBUF
, (char *) &size
, sizeof(size
)) < 0)
708 debug(50, 1) ("commSetTcpRcvbuf: FD %d, SIZE %d: %s\n",
709 fd
, size
, xstrerror());
713 commSetNonBlocking(int fd
)
717 #ifdef _SQUID_CYGWIN_
718 int nonblocking
= TRUE
;
719 if (fd_table
[fd
].type
!= FD_PIPE
) {
720 if (ioctl(fd
, FIONBIO
, &nonblocking
) < 0) {
721 debug(50, 0) ("commSetNonBlocking: FD %d: %s %D\n", fd
, xstrerror(), fd_table
[fd
].type
);
726 if ((flags
= fcntl(fd
, F_GETFL
, dummy
)) < 0) {
727 debug(50, 0) ("FD %d: fcntl F_GETFL: %s\n", fd
, xstrerror());
730 if (fcntl(fd
, F_SETFL
, flags
| SQUID_NONBLOCK
) < 0) {
731 debug(50, 0) ("commSetNonBlocking: FD %d: %s\n", fd
, xstrerror());
734 #ifdef _SQUID_CYGWIN_
737 fd_table
[fd
].flags
.nonblocking
= 1;
742 commUnsetNonBlocking(int fd
)
746 if ((flags
= fcntl(fd
, F_GETFL
, dummy
)) < 0) {
747 debug(50, 0) ("FD %d: fcntl F_GETFL: %s\n", fd
, xstrerror());
750 if (fcntl(fd
, F_SETFL
, flags
& (~SQUID_NONBLOCK
)) < 0) {
751 debug(50, 0) ("commUnsetNonBlocking: FD %d: %s\n", fd
, xstrerror());
754 fd_table
[fd
].flags
.nonblocking
= 0;
759 commSetCloseOnExec(int fd
)
764 if ((flags
= fcntl(fd
, F_GETFL
, dummy
)) < 0) {
765 debug(50, 0) ("FD %d: fcntl F_GETFL: %s\n", fd
, xstrerror());
768 if (fcntl(fd
, F_SETFD
, flags
| FD_CLOEXEC
) < 0)
769 debug(50, 0) ("FD %d: set close-on-exec failed: %s\n", fd
, xstrerror());
775 commSetTcpNoDelay(int fd
)
778 if (setsockopt(fd
, IPPROTO_TCP
, TCP_NODELAY
, (char *) &on
, sizeof(on
)) < 0)
779 debug(50, 1) ("commSetTcpNoDelay: FD %d: %s\n", fd
, xstrerror());
787 fd_table
= xcalloc(Squid_MaxFD
, sizeof(fde
));
788 /* XXX account fd_table */
789 /* Keep a few file descriptors free so that we don't run out of FD's
790 * after accepting a client but before it opens a socket or a file.
791 * Since Squid_MaxFD can be as high as several thousand, don't waste them */
792 RESERVED_FD
= XMIN(100, Squid_MaxFD
/ 4);
793 CBDATA_INIT_TYPE(ConnectStateData
);
794 comm_write_pool
= memPoolCreate("CommWriteStateData", sizeof(CommWriteStateData
));
795 conn_close_pool
= memPoolCreate("close_handler", sizeof(close_handler
));
800 commHandleWrite(int fd
, void *data
)
802 CommWriteStateData
*state
= data
;
806 debug(5, 5) ("commHandleWrite: FD %d: off %d, sz %d.\n",
807 fd
, (int) state
->offset
, state
->size
);
809 nleft
= state
->size
- state
->offset
;
810 len
= write(fd
, state
->buf
+ state
->offset
, nleft
);
811 debug(5, 5) ("commHandleWrite: write() returns %d\n", len
);
812 fd_bytes(fd
, len
, FD_WRITE
);
813 statCounter
.syscalls
.sock
.writes
++;
816 /* Note we even call write if nleft == 0 */
819 debug(5, 1) ("commHandleWrite: FD %d: write failure: connection closed with %d bytes remaining.\n", fd
, nleft
);
820 CommWriteStateCallbackAndFree(fd
, nleft
? COMM_ERROR
: COMM_OK
);
821 } else if (len
< 0) {
823 if (fd_table
[fd
].flags
.socket_eof
) {
824 debug(50, 2) ("commHandleWrite: FD %d: write failure: %s.\n",
826 CommWriteStateCallbackAndFree(fd
, COMM_ERROR
);
827 } else if (ignoreErrno(errno
)) {
828 debug(50, 10) ("commHandleWrite: FD %d: write failure: %s.\n",
836 debug(50, 2) ("commHandleWrite: FD %d: write failure: %s.\n",
838 CommWriteStateCallbackAndFree(fd
, COMM_ERROR
);
841 /* A successful write, continue */
842 state
->offset
+= len
;
843 if (state
->offset
< state
->size
) {
844 /* Not done, reinstall the write handler and write some more */
851 CommWriteStateCallbackAndFree(fd
, COMM_OK
);
858 /* Select for Writing on FD, until SIZE bytes are sent. Call
859 * *HANDLER when complete. */
861 comm_write(int fd
, char *buf
, int size
, CWCB
* handler
, void *handler_data
, FREE
* free_func
)
863 CommWriteStateData
*state
= fd_table
[fd
].rwstate
;
864 debug(5, 5) ("comm_write: FD %d: sz %d: hndl %p: data %p.\n",
865 fd
, size
, handler
, handler_data
);
867 debug(5, 1) ("comm_write: fd_table[%d].rwstate != NULL\n", fd
);
868 memPoolFree(comm_write_pool
, state
);
869 fd_table
[fd
].rwstate
= NULL
;
871 assert(state
== NULL
);
872 fd_table
[fd
].rwstate
= state
= memPoolAlloc(comm_write_pool
);
876 state
->handler
= handler
;
877 state
->handler_data
= handler_data
;
878 state
->free_func
= free_func
;
879 cbdataLock(handler_data
);
880 commSetSelect(fd
, COMM_SELECT_WRITE
, commHandleWrite
, state
, 0);
883 /* a wrapper around comm_write to allow for MemBuf to be comm_written in a snap */
885 comm_write_mbuf(int fd
, MemBuf mb
, CWCB
* handler
, void *handler_data
)
887 comm_write(fd
, mb
.buf
, mb
.size
, handler
, handler_data
, memBufFreeFunc(&mb
));
891 * hm, this might be too general-purpose for all the places we'd
895 ignoreErrno(int ierrno
)
900 #if EAGAIN != EWOULDBLOCK
916 commCloseAllSockets(void)
921 for (fd
= 0; fd
<= Biggest_FD
; fd
++) {
925 if (F
->type
!= FD_SOCKET
)
927 if (F
->flags
.ipc
) /* don't close inter-process sockets */
929 if (F
->timeout_handler
) {
930 debug(5, 5) ("commCloseAllSockets: FD %d: Calling timeout handler\n",
932 callback
= F
->timeout_handler
;
933 F
->timeout_handler
= NULL
;
934 callback(fd
, F
->timeout_data
);
936 debug(5, 5) ("commCloseAllSockets: FD %d: calling comm_close()\n", fd
);