]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/comm.cc
3 * $Id: comm.cc,v 1.304 1999/12/30 17:36:27 wessels Exp $
5 * DEBUG: section 5 Socket Functions
6 * AUTHOR: Harvest Derived
8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
9 * ----------------------------------------------------------
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 the
14 * National Science Foundation. Squid is Copyrighted (C) 1998 by
15 * Duane Wessels and the University of California San Diego. Please
16 * see the COPYRIGHT file for full details. Squid incorporates
17 * software developed and/or copyrighted by other sources. Please see
18 * 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
);
74 CommWriteStateCallbackAndFree(int fd
, int code
)
76 CommWriteStateData
*CommWriteState
= fd_table
[fd
].rwstate
;
77 CWCB
*callback
= NULL
;
79 fd_table
[fd
].rwstate
= NULL
;
80 if (CommWriteState
== NULL
)
82 if (CommWriteState
->free_func
) {
83 CommWriteState
->free_func(CommWriteState
->buf
);
84 CommWriteState
->buf
= NULL
;
86 callback
= CommWriteState
->handler
;
87 data
= CommWriteState
->handler_data
;
88 CommWriteState
->handler
= NULL
;
89 if (callback
&& cbdataValid(data
))
90 callback(fd
, CommWriteState
->buf
, CommWriteState
->offset
, code
, data
);
92 safe_free(CommWriteState
);
95 /* Return the local port associated with fd. */
97 comm_local_port(int fd
)
99 struct sockaddr_in addr
;
100 socklen_t addr_len
= 0;
101 fde
*F
= &fd_table
[fd
];
103 /* If the fd is closed already, just return */
104 if (!F
->flags
.open
) {
105 debug(5, 0) ("comm_local_port: FD %d has been closed.\n", fd
);
109 return F
->local_port
;
110 addr_len
= sizeof(addr
);
111 if (getsockname(fd
, (struct sockaddr
*) &addr
, &addr_len
)) {
112 debug(50, 1) ("comm_local_port: Failed to retrieve TCP/UDP port number for socket: FD %d: %s\n", fd
, xstrerror());
115 F
->local_port
= ntohs(addr
.sin_port
);
116 debug(5, 6) ("comm_local_port: FD %d: port %d\n", fd
, (int) F
->local_port
);
117 return F
->local_port
;
121 commBind(int s
, struct in_addr in_addr
, u_short port
)
123 struct sockaddr_in S
;
125 memset(&S
, '\0', sizeof(S
));
126 S
.sin_family
= AF_INET
;
127 S
.sin_port
= htons(port
);
128 S
.sin_addr
= in_addr
;
129 Counter
.syscalls
.sock
.binds
++;
130 if (bind(s
, (struct sockaddr
*) &S
, sizeof(S
)) == 0)
132 debug(50, 0) ("commBind: Cannot bind socket FD %d to %s:%d: %s\n",
134 S
.sin_addr
.s_addr
== INADDR_ANY
? "*" : inet_ntoa(S
.sin_addr
),
140 /* Create a socket. Default is blocking, stream (TCP) socket. IO_TYPE
141 * is OR of flags specified in comm.h. */
143 comm_open(int sock_type
,
153 /* Create socket for accepting new connections. */
154 Counter
.syscalls
.sock
.sockets
++;
155 if ((new_socket
= socket(AF_INET
, sock_type
, proto
)) < 0) {
156 /* Increase the number of reserved fd's if calls to socket()
157 * are failing because the open file table is full. This
158 * limits the number of simultaneous clients */
162 debug(50, 1) ("comm_open: socket failure: %s\n", xstrerror());
166 debug(50, 0) ("comm_open: socket failure: %s\n", xstrerror());
171 debug(5, 5) ("comm_open: FD %d is a new socket\n", new_socket
);
172 fd_open(new_socket
, FD_SOCKET
, note
);
173 F
= &fd_table
[new_socket
];
174 if (!(flags
& COMM_NOCLOEXEC
))
175 commSetCloseOnExec(new_socket
);
176 if ((flags
& COMM_REUSEADDR
))
177 commSetReuseAddr(new_socket
);
178 if (port
> (u_short
) 0) {
179 commSetNoLinger(new_socket
);
181 commSetReuseAddr(new_socket
);
183 if (addr
.s_addr
!= no_addr
.s_addr
) {
184 if (commBind(new_socket
, addr
, port
) != COMM_OK
) {
185 comm_close(new_socket
);
189 F
->local_port
= port
;
191 if (flags
& COMM_NONBLOCKING
)
192 if (commSetNonBlocking(new_socket
) == COMM_ERROR
)
195 if (sock_type
== SOCK_STREAM
)
196 commSetTcpNoDelay(new_socket
);
198 if (Config
.tcpRcvBufsz
> 0 && sock_type
== SOCK_STREAM
)
199 commSetTcpRcvbuf(new_socket
, Config
.tcpRcvBufsz
);
204 * NOTE: set the listen queue to Squid_MaxFD/4 and rely on the kernel to
205 * impose an upper limit. Solaris' listen(3n) page says it has
206 * no limit on this parameter, but sys/socket.h sets SOMAXCONN
207 * to 5. HP-UX currently has a limit of 20. SunOS is 5 and
211 comm_listen(int sock
)
214 if ((x
= listen(sock
, Squid_MaxFD
>> 2)) < 0) {
215 debug(50, 0) ("comm_listen: listen(%d, %d): %s\n",
224 commConnectStart(int fd
, const char *host
, u_short port
, CNCB
* callback
, void *data
)
226 ConnectStateData
*cs
= xcalloc(1, sizeof(ConnectStateData
));
227 debug(5, 3) ("commConnectStart: FD %d, %s:%d\n", fd
, host
, (int) port
);
228 cbdataAdd(cs
, cbdataXfree
, 0);
230 cs
->host
= xstrdup(host
);
232 cs
->callback
= callback
;
234 cbdataLock(cs
->data
);
235 comm_add_close_handler(fd
, commConnectFree
, cs
);
237 ipcache_nbgethostbyname(host
, commConnectDnsHandle
, cs
);
241 commConnectDnsHandle(const ipcache_addrs
* ia
, void *data
)
243 ConnectStateData
*cs
= data
;
244 assert(cs
->locks
== 1);
247 debug(5, 3) ("commConnectDnsHandle: Unknown host: %s\n", cs
->host
);
248 if (!dns_error_message
) {
249 dns_error_message
= "Unknown DNS error";
250 debug(5, 1) ("commConnectDnsHandle: Bad dns_error_message\n");
252 assert(dns_error_message
!= NULL
);
253 commConnectCallback(cs
, COMM_ERR_DNS
);
256 assert(ia
->cur
< ia
->count
);
257 cs
->in_addr
= ia
->in_addrs
[ia
->cur
];
258 ipcacheCycleAddr(cs
->host
, NULL
);
259 cs
->addrcount
= ia
->count
;
260 cs
->connstart
= squid_curtime
;
261 commConnectHandle(cs
->fd
, cs
);
265 commConnectCallback(ConnectStateData
* cs
, int status
)
267 CNCB
*callback
= cs
->callback
;
268 void *data
= cs
->data
;
270 comm_remove_close_handler(fd
, commConnectFree
, cs
);
273 commSetTimeout(fd
, -1, NULL
, NULL
);
274 commConnectFree(fd
, cs
);
275 if (cbdataValid(data
))
276 callback(fd
, status
, data
);
281 commConnectFree(int fd
, void *data
)
283 ConnectStateData
*cs
= data
;
284 debug(5, 3) ("commConnectFree: FD %d\n", fd
);
286 ipcacheUnregister(cs
->host
, cs
);
288 cbdataUnlock(cs
->data
);
293 /* Reset FD so that we can connect() again */
295 commResetFD(ConnectStateData
* cs
)
298 if (!cbdataValid(cs
->data
))
300 Counter
.syscalls
.sock
.sockets
++;
301 fd2
= socket(AF_INET
, SOCK_STREAM
, 0);
302 Counter
.syscalls
.sock
.sockets
++;
304 debug(5, 0) ("commResetFD: socket: %s\n", xstrerror());
305 if (ENFILE
== errno
|| EMFILE
== errno
)
309 if (dup2(fd2
, cs
->fd
) < 0) {
310 debug(5, 0) ("commResetFD: dup2: %s\n", xstrerror());
311 if (ENFILE
== errno
|| EMFILE
== errno
)
316 fd_table
[cs
->fd
].flags
.called_connect
= 0;
318 * yuck, this has assumptions about comm_open() arguments for
319 * the original socket
321 commSetCloseOnExec(cs
->fd
);
322 if (Config
.Addrs
.tcp_outgoing
.s_addr
!= no_addr
.s_addr
) {
323 if (commBind(cs
->fd
, Config
.Addrs
.tcp_outgoing
, 0) != COMM_OK
) {
327 commSetNonBlocking(cs
->fd
);
329 commSetTcpNoDelay(cs
->fd
);
331 if (Config
.tcpRcvBufsz
> 0)
332 commSetTcpRcvbuf(cs
->fd
, Config
.tcpRcvBufsz
);
337 commRetryConnect(ConnectStateData
* cs
)
339 assert(cs
->addrcount
> 0);
340 if (cs
->addrcount
== 1) {
341 if (cs
->tries
>= Config
.retry
.maxtries
)
343 if (squid_curtime
- cs
->connstart
> Config
.Timeout
.connect
)
346 if (cs
->tries
> cs
->addrcount
)
349 return commResetFD(cs
);
352 /* Connect SOCK to specified DEST_PORT at DEST_HOST. */
354 commConnectHandle(int fd
, void *data
)
356 ConnectStateData
*cs
= data
;
357 if (cs
->S
.sin_addr
.s_addr
== 0) {
358 cs
->S
.sin_family
= AF_INET
;
359 cs
->S
.sin_addr
= cs
->in_addr
;
360 cs
->S
.sin_port
= htons(cs
->port
);
361 if (Config
.onoff
.log_fqdn
)
362 fqdncache_gethostbyaddr(cs
->S
.sin_addr
, FQDN_LOOKUP_IF_MISS
);
364 switch (comm_connect_addr(fd
, &cs
->S
)) {
365 case COMM_INPROGRESS
:
366 debug(5, 5) ("commConnectHandle: FD %d: COMM_INPROGRESS\n", fd
);
367 commSetSelect(fd
, COMM_SELECT_WRITE
, commConnectHandle
, cs
, 0);
370 ipcacheMarkGoodAddr(cs
->host
, cs
->S
.sin_addr
);
371 commConnectCallback(cs
, COMM_OK
);
375 ipcacheMarkBadAddr(cs
->host
, cs
->S
.sin_addr
);
376 if (Config
.onoff
.test_reachability
)
377 netdbDeleteAddrNetwork(cs
->S
.sin_addr
);
378 if (commRetryConnect(cs
)) {
380 ipcache_nbgethostbyname(cs
->host
, commConnectDnsHandle
, cs
);
382 commConnectCallback(cs
, COMM_ERR_CONNECT
);
389 commSetTimeout(int fd
, int timeout
, PF
* handler
, void *data
)
392 debug(5, 3) ("commSetTimeout: FD %d timeout %d\n", fd
, timeout
);
394 assert(fd
< Squid_MaxFD
);
396 assert(F
->flags
.open
);
398 F
->timeout_handler
= NULL
;
399 F
->timeout_data
= NULL
;
400 return F
->timeout
= 0;
402 assert(handler
|| F
->timeout_handler
);
403 if (handler
|| data
) {
404 F
->timeout_handler
= handler
;
405 F
->timeout_data
= data
;
407 return F
->timeout
= squid_curtime
+ (time_t) timeout
;
411 comm_connect_addr(int sock
, const struct sockaddr_in
*address
)
413 int status
= COMM_OK
;
414 fde
*F
= &fd_table
[sock
];
418 assert(ntohs(address
->sin_port
) != 0);
419 /* Establish connection. */
421 if (!F
->flags
.called_connect
) {
422 F
->flags
.called_connect
= 1;
423 Counter
.syscalls
.sock
.connects
++;
424 x
= connect(sock
, (struct sockaddr
*) address
, sizeof(*address
));
426 debug(5, 9) ("connect FD %d: %s\n", sock
, xstrerror());
428 #if defined(_SQUID_NEWSOS6_)
429 /* Makoto MATSUSHITA <matusita@ics.es.osaka-u.ac.jp> */
430 connect(sock
, (struct sockaddr
*) address
, sizeof(*address
));
431 if (errno
== EINVAL
) {
432 errlen
= sizeof(err
);
433 x
= getsockopt(sock
, SOL_SOCKET
, SO_ERROR
, &err
, &errlen
);
438 errlen
= sizeof(err
);
439 x
= getsockopt(sock
, SOL_SOCKET
, SO_ERROR
, &err
, &errlen
);
442 #if defined(_SQUID_SOLARIS_)
444 * Solaris 2.4's socket emulation doesn't allow you
445 * to determine the error from a failed non-blocking
446 * connect and just returns EPIPE. Create a fake
447 * error message for connect. -- fenner@parc.xerox.com
449 if (x
< 0 && errno
== EPIPE
)
454 if (errno
== 0 || errno
== EISCONN
)
456 else if (ignoreErrno(errno
))
457 status
= COMM_INPROGRESS
;
460 xstrncpy(F
->ipaddr
, inet_ntoa(address
->sin_addr
), 16);
461 F
->remote_port
= ntohs(address
->sin_port
);
462 if (status
== COMM_OK
) {
463 debug(5, 10) ("comm_connect_addr: FD %d connected to %s:%d\n",
464 sock
, F
->ipaddr
, F
->remote_port
);
465 } else if (status
== COMM_INPROGRESS
) {
466 debug(5, 10) ("comm_connect_addr: FD %d connection pending\n", sock
);
471 /* Wait for an incoming connection on FD. FD should be a socket returned
472 * from comm_listen. */
474 comm_accept(int fd
, struct sockaddr_in
*pn
, struct sockaddr_in
*me
)
477 struct sockaddr_in P
;
478 struct sockaddr_in M
;
482 Counter
.syscalls
.sock
.accepts
++;
483 if ((sock
= accept(fd
, (struct sockaddr
*) &P
, &Slen
)) < 0) {
484 if (ignoreErrno(errno
)) {
485 debug(50, 5) ("comm_accept: FD %d: %s\n", fd
, xstrerror());
486 return COMM_NOMESSAGE
;
487 } else if (ENFILE
== errno
|| EMFILE
== errno
) {
488 debug(50, 3) ("comm_accept: FD %d: %s\n", fd
, xstrerror());
491 debug(50, 1) ("comm_accept: FD %d: %s\n", fd
, xstrerror());
498 memset(&M
, '\0', Slen
);
499 getsockname(sock
, (struct sockaddr
*) &M
, &Slen
);
502 commSetCloseOnExec(sock
);
504 fd_open(sock
, FD_SOCKET
, "HTTP Request");
506 xstrncpy(F
->ipaddr
, inet_ntoa(P
.sin_addr
), 16);
507 F
->remote_port
= htons(P
.sin_port
);
508 F
->local_port
= htons(M
.sin_port
);
509 commSetNonBlocking(sock
);
514 commCallCloseHandlers(int fd
)
516 fde
*F
= &fd_table
[fd
];
518 debug(5, 5) ("commCallCloseHandlers: FD %d\n", fd
);
519 while ((ch
= F
->close_handler
) != NULL
) {
520 F
->close_handler
= ch
->next
;
521 debug(5, 5) ("commCallCloseHandlers: ch->handler=%p\n", ch
->handler
);
522 if (cbdataValid(ch
->data
))
523 ch
->handler(fd
, ch
->data
);
524 cbdataUnlock(ch
->data
);
531 commLingerClose(int fd
, void *unused
)
533 LOCAL_ARRAY(char, buf
, 1024);
535 n
= read(fd
, buf
, 1024);
537 debug(5, 3) ("commLingerClose: FD %d read: %s\n", fd
, xstrerror());
542 commLingerTimeout(int fd
, void *unused
)
544 debug(5, 3) ("commLingerTimeout: FD %d\n", fd
);
552 comm_lingering_close(int fd
)
554 if (shutdown(fd
, 1) < 0) {
558 fd_note(fd
, "lingering close");
559 commSetTimeout(fd
, 10, commLingerTimeout
, NULL
);
560 commSetSelect(fd
, COMM_SELECT_READ
, commLingerClose
, NULL
, 0);
568 debug(5, 5) ("comm_close: FD %d\n", fd
);
570 assert(fd
< Squid_MaxFD
);
572 if (F
->flags
.closing
)
574 if (shutting_down
&& (!F
->flags
.open
|| F
->type
== FD_FILE
))
576 assert(F
->flags
.open
);
577 assert(F
->type
!= FD_FILE
);
578 F
->flags
.closing
= 1;
579 CommWriteStateCallbackAndFree(fd
, COMM_ERR_CLOSING
);
580 commCallCloseHandlers(fd
);
581 if (F
->uses
) /* assume persistent connect count */
582 pconnHistCount(1, F
->uses
);
583 fd_close(fd
); /* update fdstat */
585 Counter
.syscalls
.sock
.closes
++;
588 /* Send a udp datagram to specified TO_ADDR. */
590 comm_udp_sendto(int fd
,
591 const struct sockaddr_in
*to_addr
,
597 Counter
.syscalls
.sock
.sendtos
++;
598 x
= sendto(fd
, buf
, len
, 0, (struct sockaddr
*) to_addr
, addr_len
);
601 if (ECONNREFUSED
!= errno
)
603 debug(50, 1) ("comm_udp_sendto: FD %d, %s, port %d: %s\n",
605 inet_ntoa(to_addr
->sin_addr
),
606 (int) htons(to_addr
->sin_port
),
614 commSetDefer(int fd
, DEFER
* func
, void *data
)
616 fde
*F
= &fd_table
[fd
];
617 F
->defer_check
= func
;
618 F
->defer_data
= data
;
622 commSetSelect(int fd
, unsigned int type
, PF
* handler
, void *client_data
, time_t timeout
)
624 fde
*F
= &fd_table
[fd
];
626 assert(F
->flags
.open
);
627 debug(5, 5) ("commSetSelect: FD %d type %d\n", fd
, type
);
628 if (type
& COMM_SELECT_READ
) {
629 F
->read_handler
= handler
;
630 F
->read_data
= client_data
;
631 commUpdateReadBits(fd
, handler
);
633 if (type
& COMM_SELECT_WRITE
) {
634 F
->write_handler
= handler
;
635 F
->write_data
= client_data
;
636 commUpdateWriteBits(fd
, handler
);
639 F
->timeout
= squid_curtime
+ timeout
;
643 comm_add_close_handler(int fd
, PF
* handler
, void *data
)
645 close_handler
*new = xmalloc(sizeof(*new));
647 debug(5, 5) ("comm_add_close_handler: FD %d, handler=%p, data=%p\n",
649 for (c
= fd_table
[fd
].close_handler
; c
; c
= c
->next
)
650 assert(c
->handler
!= handler
|| c
->data
!= data
);
651 new->handler
= handler
;
653 new->next
= fd_table
[fd
].close_handler
;
654 fd_table
[fd
].close_handler
= new;
659 comm_remove_close_handler(int fd
, PF
* handler
, void *data
)
662 close_handler
*last
= NULL
;
663 /* Find handler in list */
664 debug(5, 5) ("comm_remove_close_handler: FD %d, handler=%p, data=%p\n",
666 for (p
= fd_table
[fd
].close_handler
; p
!= NULL
; last
= p
, p
= p
->next
)
667 if (p
->handler
== handler
&& p
->data
== data
)
668 break; /* This is our handler */
670 /* Remove list entry */
672 last
->next
= p
->next
;
674 fd_table
[fd
].close_handler
= p
->next
;
675 cbdataUnlock(p
->data
);
680 commSetNoLinger(int fd
)
683 L
.l_onoff
= 0; /* off */
685 if (setsockopt(fd
, SOL_SOCKET
, SO_LINGER
, (char *) &L
, sizeof(L
)) < 0)
686 debug(50, 0) ("commSetNoLinger: FD %d: %s\n", fd
, xstrerror());
687 fd_table
[fd
].flags
.nolinger
= 1;
691 commSetReuseAddr(int fd
)
694 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &on
, sizeof(on
)) < 0)
695 debug(50, 1) ("commSetReuseAddr: FD %d: %s\n", fd
, xstrerror());
699 commSetTcpRcvbuf(int fd
, int size
)
701 if (setsockopt(fd
, SOL_SOCKET
, SO_RCVBUF
, (char *) &size
, sizeof(size
)) < 0)
702 debug(50, 1) ("commSetTcpRcvbuf: FD %d, SIZE %d: %s\n",
703 fd
, size
, xstrerror());
707 commSetNonBlocking(int fd
)
711 if ((flags
= fcntl(fd
, F_GETFL
, dummy
)) < 0) {
712 debug(50, 0) ("FD %d: fcntl F_GETFL: %s\n", fd
, xstrerror());
715 if (fcntl(fd
, F_SETFL
, flags
| SQUID_NONBLOCK
) < 0) {
716 debug(50, 0) ("commSetNonBlocking: FD %d: %s\n", fd
, xstrerror());
719 fd_table
[fd
].flags
.nonblocking
= 1;
724 commUnsetNonBlocking(int fd
)
728 if ((flags
= fcntl(fd
, F_GETFL
, dummy
)) < 0) {
729 debug(50, 0) ("FD %d: fcntl F_GETFL: %s\n", fd
, xstrerror());
732 if (fcntl(fd
, F_SETFL
, flags
& (~SQUID_NONBLOCK
)) < 0) {
733 debug(50, 0) ("commUnsetNonBlocking: FD %d: %s\n", fd
, xstrerror());
736 fd_table
[fd
].flags
.nonblocking
= 0;
741 commSetCloseOnExec(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_SETFD
, flags
| FD_CLOEXEC
) < 0)
751 debug(50, 0) ("FD %d: set close-on-exec failed: %s\n", fd
, xstrerror());
757 commSetTcpNoDelay(int fd
)
760 if (setsockopt(fd
, IPPROTO_TCP
, TCP_NODELAY
, (char *) &on
, sizeof(on
)) < 0)
761 debug(50, 1) ("commSetTcpNoDelay: FD %d: %s\n", fd
, xstrerror());
769 fd_table
= xcalloc(Squid_MaxFD
, sizeof(fde
));
770 /* XXX account fd_table */
771 /* Keep a few file descriptors free so that we don't run out of FD's
772 * after accepting a client but before it opens a socket or a file.
773 * Since Squid_MaxFD can be as high as several thousand, don't waste them */
774 RESERVED_FD
= XMIN(100, Squid_MaxFD
/ 4);
779 commHandleWrite(int fd
, void *data
)
781 CommWriteStateData
*state
= data
;
785 debug(5, 5) ("commHandleWrite: FD %d: off %d, sz %d.\n",
786 fd
, (int) state
->offset
, state
->size
);
788 nleft
= state
->size
- state
->offset
;
789 len
= write(fd
, state
->buf
+ state
->offset
, nleft
);
790 debug(5, 5) ("commHandleWrite: write() returns %d\n", len
);
791 fd_bytes(fd
, len
, FD_WRITE
);
792 Counter
.syscalls
.sock
.writes
++;
795 /* Note we even call write if nleft == 0 */
798 debug(5, 1) ("commHandleWrite: FD %d: write failure: connection closed with %d bytes remaining.\n", fd
, nleft
);
799 CommWriteStateCallbackAndFree(fd
, nleft
? COMM_ERROR
: COMM_OK
);
800 } else if (len
< 0) {
802 if (fd_table
[fd
].flags
.socket_eof
) {
803 debug(50, 2) ("commHandleWrite: FD %d: write failure: %s.\n",
805 CommWriteStateCallbackAndFree(fd
, COMM_ERROR
);
806 } else if (ignoreErrno(errno
)) {
807 debug(50, 10) ("commHandleWrite: FD %d: write failure: %s.\n",
815 debug(50, 2) ("commHandleWrite: FD %d: write failure: %s.\n",
817 CommWriteStateCallbackAndFree(fd
, COMM_ERROR
);
820 /* A successful write, continue */
821 state
->offset
+= len
;
822 if (state
->offset
< state
->size
) {
823 /* Not done, reinstall the write handler and write some more */
830 CommWriteStateCallbackAndFree(fd
, COMM_OK
);
837 /* Select for Writing on FD, until SIZE bytes are sent. Call
838 * * HANDLER when complete. */
840 comm_write(int fd
, char *buf
, int size
, CWCB
* handler
, void *handler_data
, FREE
* free_func
)
842 CommWriteStateData
*state
= fd_table
[fd
].rwstate
;
843 debug(5, 5) ("comm_write: FD %d: sz %d: hndl %p: data %p.\n",
844 fd
, size
, handler
, handler_data
);
846 debug(5, 1) ("comm_write: fd_table[%d].rwstate != NULL\n", fd
);
848 fd_table
[fd
].rwstate
= NULL
;
850 assert(state
== NULL
);
851 fd_table
[fd
].rwstate
= state
= xcalloc(1, sizeof(CommWriteStateData
));
855 state
->handler
= handler
;
856 state
->handler_data
= handler_data
;
857 state
->free_func
= free_func
;
858 cbdataLock(handler_data
);
859 commSetSelect(fd
, COMM_SELECT_WRITE
, commHandleWrite
, state
, 0);
862 /* a wrapper around comm_write to allow for MemBuf to be comm_written in a snap */
864 comm_write_mbuf(int fd
, MemBuf mb
, CWCB
* handler
, void *handler_data
)
866 comm_write(fd
, mb
.buf
, mb
.size
, handler
, handler_data
, memBufFreeFunc(&mb
));
870 * hm, this might be too general-purpose for all the places we'd
874 ignoreErrno(int ierrno
)
879 #if EAGAIN != EWOULDBLOCK
895 commCloseAllSockets(void)
900 for (fd
= 0; fd
<= Biggest_FD
; fd
++) {
904 if (F
->type
!= FD_SOCKET
)
906 if (F
->flags
.ipc
) /* don't close inter-process sockets */
908 if (F
->timeout_handler
) {
909 debug(5, 5) ("commCloseAllSockets: FD %d: Calling timeout handler\n",
911 callback
= F
->timeout_handler
;
912 F
->timeout_handler
= NULL
;
913 callback(fd
, F
->timeout_data
);
915 debug(5, 5) ("commCloseAllSockets: FD %d: calling comm_close()\n", fd
);