]> git.ipfire.org Git - thirdparty/squid.git/blame - src/comm.cc
recvfrom() -> comm_recvfrom()
[thirdparty/squid.git] / src / comm.cc
CommitLineData
da2b3a17 1
30a4f2a8 2/*
ce767c23 3 * $Id: comm.cc,v 1.341 2002/10/21 05:38:32 adrian 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"
c4b7a5a9 37#include "StoreIOBuffer.h"
38#include "comm.h"
090089c4 39
b671cc68 40#if defined(_SQUID_CYGWIN_)
41#include <sys/ioctl.h>
42#endif
30a4f2a8 43#ifdef HAVE_NETINET_TCP_H
44#include <netinet/tcp.h>
45#endif
090089c4 46
f88211e8 47typedef struct {
48 char *host;
49 u_short port;
50 struct sockaddr_in S;
51 CNCB *callback;
52 void *data;
f88211e8 53 struct in_addr in_addr;
54 int locks;
03a1ee42 55 int fd;
22c653cd 56 int tries;
57 int addrcount;
58 int connstart;
f88211e8 59} ConnectStateData;
60
090089c4 61/* STATIC */
e6ccf245 62static comm_err_t commBind(int s, struct in_addr, u_short port);
f5b8bbc4 63static void commSetReuseAddr(int);
64static void commSetNoLinger(int);
3d7e9d7c 65static void CommWriteStateCallbackAndFree(int fd, comm_err_t code);
30a4f2a8 66#ifdef TCP_NODELAY
f5b8bbc4 67static void commSetTcpNoDelay(int);
30a4f2a8 68#endif
f5b8bbc4 69static void commSetTcpRcvbuf(int, int);
f88211e8 70static PF commConnectFree;
03a1ee42 71static PF commConnectHandle;
72static PF commHandleWrite;
edeb28fd 73static IPH commConnectDnsHandle;
3d7e9d7c 74static void commConnectCallback(ConnectStateData * cs, comm_err_t status);
22c653cd 75static int commResetFD(ConnectStateData * cs);
76static int commRetryConnect(ConnectStateData * cs);
28c60158 77CBDATA_TYPE(ConnectStateData);
723123a9 78
c4b7a5a9 79
80struct _fdc_t {
81 int active;
82 dlink_list CommCallbackList;
83 struct {
84 char *buf;
85 int size;
86 IOCB *handler;
87 void *handler_data;
88 } read;
89 struct {
90 struct sockaddr_in me;
91 struct sockaddr_in pn;
92 IOACB *handler;
93 void *handler_data;
94 } accept;
95 struct CommFiller {
96 StoreIOBuffer requestedData;
97 size_t amountDone;
98 IOFCB *handler;
99 void *handler_data;
100 } fill;
101
102};
103typedef struct _fdc_t fdc_t;
104
105typedef enum {
106 COMM_CB_READ = 1,
107 COMM_CB_WRITE,
108 COMM_CB_ACCEPT,
109 COMM_CB_FILL
110} comm_callback_t;
111
112struct _CommCallbackData {
113 comm_callback_t type;
114 dlink_node fd_node;
115 dlink_node h_node;
116 int fd;
117 int newfd; /* for accept() */
118 char *buf;
119 int retval;
120 union {
121 IOCB *r_callback;
122 IOACB *a_callback;
123 IOFCB *f_callback;
124 } c;
125 void *callback_data;
126 comm_err_t errcode;
127 int xerrno;
128 int seqnum;
129 struct sockaddr_in me;
130 struct sockaddr_in pn;
131 StoreIOBuffer sb;
132};
133typedef struct _CommCallbackData CommCallbackData;
134
135struct _fd_debug_t {
136 char *close_file;
137 int close_line;
138};
139typedef struct _fd_debug_t fd_debug_t;
140
723123a9 141static MemPool *comm_write_pool = NULL;
58cd5bbd 142static MemPool *conn_close_pool = NULL;
c4b7a5a9 143static MemPool *comm_callback_pool = NULL;
144fdc_t *fdc_table = NULL;
145fd_debug_t *fdd_table = NULL;
146dlink_list CommCallbackList;
147static int CommCallbackSeqnum = 1;
148
149
150/* New and improved stuff */
151
152/*
153 * return whether there are entries in the callback queue
154 */
155int
156comm_existsiocallback(void)
157{
158 return CommCallbackList.head == NULL;
159}
160
161/*
162 * add an IO callback
163 *
164 * IO callbacks are added when we want to notify someone that some IO
165 * has finished but we don't want to risk re-entering a non-reentrant
166 * code block.
167 */
168static void
169comm_addreadcallback(int fd, IOCB *callback, char *buf, size_t retval, comm_err_t errcode,
170 int xerrno, void *callback_data)
171{
172 CommCallbackData *cio;
173
174 assert(fdc_table[fd].active == 1);
175
176 /* Allocate a new struct */
177 cio = (CommCallbackData *)memPoolAlloc(comm_callback_pool);
178
179 /* Throw our data into it */
180 cio->fd = fd;
181 cio->retval = retval;
182 cio->xerrno = xerrno;
183 cio->errcode = errcode;
184 cio->c.r_callback = callback;
185 cio->callback_data = callback_data;
186 cio->seqnum = CommCallbackSeqnum;
187 cio->buf = buf;
188 cio->type = COMM_CB_READ;
189
190 /* Add it to the end of the list */
191 dlinkAddTail(cio, &(cio->h_node), &CommCallbackList);
192
193 /* and add it to the end of the fd list */
194 dlinkAddTail(cio, &(cio->fd_node), &(fdc_table[fd].CommCallbackList));
195
196}
197
198
199static void
200comm_addacceptcallback(int fd, int newfd, IOACB *callback, struct sockaddr_in *pn,
201 struct sockaddr_in *me, comm_err_t errcode, int xerrno, void *callback_data)
202{
203 CommCallbackData *cio;
204
205 assert(fdc_table[fd].active == 1);
206
207 /* Allocate a new struct */
208 cio = (CommCallbackData *)memPoolAlloc(comm_callback_pool);
209
210 /* Throw our data into it */
211 cio->fd = fd;
212 cio->xerrno = xerrno;
213 cio->errcode = errcode;
214 cio->c.a_callback = callback;
215 cio->callback_data = callback_data;
216 cio->seqnum = CommCallbackSeqnum;
217 cio->type = COMM_CB_ACCEPT;
218 cio->newfd = newfd;
219 cio->pn = *pn;
220 cio->me = *me;
221
222 /* Add it to the end of the list */
223 dlinkAddTail(cio, &(cio->h_node), &CommCallbackList);
224
225 /* and add it to the end of the fd list */
226 dlinkAddTail(cio, &(cio->fd_node), &(fdc_table[fd].CommCallbackList));
227
228}
229
230static void
231comm_add_fill_callback(int fd, size_t retval, comm_err_t errcode, int xerrno)
232{
233 CommCallbackData *cio;
234
235 assert(fdc_table[fd].active == 1);
236
237 /* Allocate a new struct */
238 cio = (CommCallbackData *)memPoolAlloc(comm_callback_pool);
239
240 /* Throw our data into it */
241 cio->fd = fd;
242 cio->xerrno = xerrno;
243 cio->errcode = errcode;
244 cio->c.f_callback = fdc_table[fd].fill.handler;
245 cio->callback_data = fdc_table[fd].fill.handler_data;
246 cio->seqnum = CommCallbackSeqnum;
247 cio->type = COMM_CB_FILL;
248 /* retval not used */
249 cio->retval = -1;
250 cio->sb = fdc_table[fd].fill.requestedData;
251 cio->sb.length = retval;
252 /* Clear out fd state */
253 fdc_table[fd].fill.handler = NULL;
254 fdc_table[fd].fill.handler_data = NULL;
255
256 /* Add it to the end of the list */
257 dlinkAddTail(cio, &(cio->h_node), &CommCallbackList);
258
259 /* and add it to the end of the fd list */
260 dlinkAddTail(cio, &(cio->fd_node), &(fdc_table[fd].CommCallbackList));
261}
262
263
264
265
266static void
267comm_call_io_callback(CommCallbackData *cio)
268{
269 switch(cio->type) {
270 case COMM_CB_READ:
271 cio->c.r_callback(cio->fd, cio->buf, cio->retval, cio->errcode, cio->xerrno,
272 cio->callback_data);
273 break;
274 case COMM_CB_WRITE:
275 fatal("write comm hasn't been implemented yet!");
276 break;
277 case COMM_CB_ACCEPT:
278 cio->c.a_callback(cio->fd, cio->newfd, &cio->me, &cio->pn, cio->errcode,
279 cio->xerrno, cio->callback_data);
280 break;
281 case COMM_CB_FILL:
282 cio->c.f_callback(cio->fd, cio->sb, cio->errcode,
283 cio->xerrno, cio->callback_data);
284 break;
285 default:
286 fatal("unknown comm io callback type!");
287 break;
288 };
289}
290
291
292/*
293 * call the IO callbacks
294 *
295 * This should be called before comm_select() so code can attempt to
296 * initiate some IO.
297 *
298 * When io callbacks are added, they are added with the current
299 * sequence number. The sequence number is incremented in this routine -
300 * since callbacks are added to the _tail_ of the list, when we hit a
301 * callback with a seqnum _not_ what it was when we entered this routine,
302 * we can stop.
303 */
304void
305comm_calliocallback(void)
306{
307 CommCallbackData *cio;
308 dlink_node *node;
309 int oldseqnum = CommCallbackSeqnum;
310
311 /* Call our callbacks until we hit NULL or the seqnum changes */
312 while (CommCallbackList.head != NULL) {
313 node = (dlink_node *)CommCallbackList.head;
314 cio = (CommCallbackData *)node->data;
315
316 /* If seqnum isn't the same, its time to die */
317 if (cio->seqnum != oldseqnum)
318 break; /* we've hit newly-added events */
319
320 assert(fdc_table[cio->fd].active == 1);
321
322 dlinkDelete(&cio->h_node, &CommCallbackList);
323 dlinkDelete(&cio->fd_node, &(fdc_table[cio->fd].CommCallbackList));
324 comm_call_io_callback(cio);
325 memPoolFree(comm_callback_pool, cio);
326 }
327}
328
329
330/*
331 * Queue a callback
332 */
333static void
334comm_read_callback(int fd, int retval, comm_err_t errcode, int xerrno)
335{
336 fdc_t *Fc = &fdc_table[fd];
337
338 assert(Fc->read.handler != NULL);
339
340 comm_addreadcallback(fd, Fc->read.handler, Fc->read.buf, retval, errcode, xerrno,
341 Fc->read.handler_data);
342 Fc->read.handler = NULL;
343 Fc->read.handler_data = NULL;
344}
345
346/*
347 * Attempt a read
348 *
349 * If the read attempt succeeds or fails, call the callback.
350 * Else, wait for another IO notification.
351 */
352static void
353comm_read_try(int fd, void *data)
354{
355 fdc_t *Fc = &fdc_table[fd];
356 int retval;
357
358 /* make sure we actually have a callback */
359 assert(Fc->read.handler != NULL);
360
361 /* Attempt a read */
362 statCounter.syscalls.sock.reads++;
363 retval = FD_READ_METHOD(fd, Fc->read.buf, Fc->read.size);
364 if (retval < 0 && !ignoreErrno(errno)) {
365 comm_read_callback(fd, -1, COMM_ERROR, errno);
366 return;
367 };
368
369 /* See if we read anything */
370 /* Note - read 0 == socket EOF, which is a valid read */
371 if (retval >= 0) {
372 fd_bytes(fd, retval, FD_READ);
373 comm_read_callback(fd, retval, COMM_OK, 0);
374 return;
375 }
376
377 /* Nope, register for some more IO */
378 commSetSelect(fd, COMM_SELECT_READ, comm_read_try, NULL, 0);
379}
380
381/*
382 * Queue a read. handler/handler_data are called when the read
383 * completes, on error, or on file descriptor close.
384 */
385void
386comm_read(int fd, char *buf, int size, IOCB *handler, void *handler_data)
387{
388 /* Make sure we're not reading anything and we're not closing */
389 assert(fdc_table[fd].active == 1);
390 assert(fdc_table[fd].read.handler == NULL);
391 assert(!fd_table[fd].flags.closing);
392
393 /* Queue a read */
394 fdc_table[fd].read.buf = buf;
395 fdc_table[fd].read.size = size;
396 fdc_table[fd].read.handler = handler;
397 fdc_table[fd].read.handler_data = handler_data;
398
399#if OPTIMISTIC_IO
400 comm_read_try(fd, NULL);
401#else
402 /* Register intrest in a FD read */
403 commSetSelect(fd, COMM_SELECT_READ, comm_read_try, NULL, 0);
404#endif
405}
406
407static void
408comm_fill_read(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
409{
410 /* TODO use a reference to the table entry, or use C++ :] */
411 StoreIOBuffer *sb;
412 _fdc_t::CommFiller *fill;
413 assert(fdc_table[fd].active == 1);
414
415 if (flag != COMM_OK) {
416 /* Error! */
417 /* XXX This was -1 below, but -1 can't be used for size_t parameters.
418 * The callback should set -1 to the client if needed based on the flags
419 */
420 comm_add_fill_callback(fd, 0, flag, xerrno);
421 return;
422 }
423 /* flag is COMM_OK */
424 /* We handle EOFs as read lengths of 0! Its eww, but its consistent */
425 fill = &fdc_table[fd].fill;
426 fill->amountDone += len;
427 sb = &fdc_table[fd].fill.requestedData;
428 assert(fill->amountDone <= sb->length);
429 comm_add_fill_callback(fd, fill->amountDone, COMM_OK, 0);
430}
431
432/*
433 * Try filling a StoreIOBuffer with some data, and call a callback when successful
434 */
435void
436comm_fill_immediate(int fd, StoreIOBuffer sb, IOFCB *callback, void *data)
437{
438 assert(fdc_table[fd].fill.handler == NULL);
439 /* prevent confusion */
440 assert (sb.offset == 0);
441
442 /* If we don't have any data, record details and schedule a read */
443 fdc_table[fd].fill.handler = callback;
444 fdc_table[fd].fill.handler_data = data;
445 fdc_table[fd].fill.requestedData = sb;
446 fdc_table[fd].fill.amountDone = 0;
447
448 comm_read(fd, sb.data, sb.length, comm_fill_read, NULL);
449}
450
451
452/*
453 * Empty the read buffers
454 *
455 * This is a magical routine that empties the read buffers.
456 * Under some platforms (Linux) if a buffer has data in it before
457 * you call close(), the socket will hang and take quite a while
458 * to timeout.
459 */
460static void
461comm_empty_os_read_buffers(int fd)
462{
463#ifdef _SQUID_LINUX_
464 /* prevent those nasty RST packets */
465 char buf[SQUID_TCP_SO_RCVBUF];
466 if (fd_table[fd].flags.nonblocking == 1)
467 while (FD_READ_METHOD(fd, buf, SQUID_TCP_SO_RCVBUF) > 0);
468#endif
469}
470
471
472/*
473 * Return whether a file descriptor has any pending read request callbacks
474 *
475 * Assumptions: the fd is open (ie, its not closing)
476 */
477int
478comm_has_pending_read_callback(int fd)
479{
480 dlink_node *node;
481 CommCallbackData *cd;
482
483 assert(fd_table[fd].flags.open == 1);
484 assert(fdc_table[fd].active == 1);
485
486 /*
487 * XXX I don't like having to walk the list!
488 * Instead, if this routine is called often enough, we should
489 * also maintain a linked list of _read_ events - we can just
490 * check if the list head a HEAD..
491 * - adrian
492 */
493 node = fdc_table[fd].CommCallbackList.head;
494 while (node != NULL) {
495 cd = (CommCallbackData *)node->data;
496 if (cd->type == COMM_CB_READ)
497 return 1;
498 node = node->next;
499 }
500
501 /* Not found */
502 return 0;
503}
504
505/*
506 * return whether a file descriptor has a read handler
507 *
508 * Assumptions: the fd is open
509 */
510int
511comm_has_pending_read(int fd)
512{
513 assert(fd_table[fd].flags.open == 1);
514 assert(fdc_table[fd].active == 1);
515
516 return (fdc_table[fd].read.handler != NULL);
517}
518
519/*
520 * Cancel a pending read. Assert that we have the right parameters,
521 * and that there are no pending read events!
522 */
523void
524comm_read_cancel(int fd, IOCB *callback, void *data)
525{
526 assert(fd_table[fd].flags.open == 1);
527 assert(fdc_table[fd].active == 1);
528
529 assert(fdc_table[fd].read.handler == callback);
530 assert(fdc_table[fd].read.handler_data == data);
531
532 assert(!comm_has_pending_read_callback(fd));
533
534 /* Ok, we can be reasonably sure we won't lose any data here! */
535
536 /* Delete the callback */
537 fdc_table[fd].read.handler = NULL;
538 fdc_table[fd].read.handler_data = NULL;
539}
540
541
542void
543fdc_open(int fd, unsigned int type, char *desc)
544{
545 assert(fdc_table[fd].active == 0);
546
547 fdc_table[fd].active = 1;
548 fd_open(fd, type, desc);
549}
550
551
ce767c23 552/*
553 * synchronous wrapper around udp socket functions
554 */
555
556int
557comm_recvfrom(int fd, void *buf, size_t len, int flags,
558 struct sockaddr *from, socklen_t *fromlen)
559{
560 statCounter.syscalls.sock.recvfroms++;
561 return recvfrom(fd, buf, len, flags, from, fromlen);
562}
563
564
565
c4b7a5a9 566/* Older stuff */
309ad3b6 567
b8d8561b 568static void
3d7e9d7c 569CommWriteStateCallbackAndFree(int fd, comm_err_t code)
9864ee44 570{
f17936ab 571 CommWriteStateData *CommWriteState = fd_table[fd].rwstate;
572 CWCB *callback = NULL;
fa80a8ef 573 void *cbdata;
a56a3abe 574 fd_table[fd].rwstate = NULL;
f17936ab 575 if (CommWriteState == NULL)
9864ee44 576 return;
c0dec081 577 if (CommWriteState->free_func) {
729dd65c 578 FREE *free_func = CommWriteState->free_func;
579 void *free_buf = CommWriteState->buf;
580 CommWriteState->free_func = NULL;
f17936ab 581 CommWriteState->buf = NULL;
729dd65c 582 free_func(free_buf);
9864ee44 583 }
f17936ab 584 callback = CommWriteState->handler;
585 CommWriteState->handler = NULL;
fa80a8ef 586 if (callback && cbdataReferenceValidDone(CommWriteState->handler_data, &cbdata))
587 callback(fd, CommWriteState->buf, CommWriteState->offset, code, cbdata);
723123a9 588 memPoolFree(comm_write_pool, CommWriteState);
9864ee44 589}
590
090089c4 591/* Return the local port associated with fd. */
b8d8561b 592u_short
593comm_local_port(int fd)
090089c4 594{
595 struct sockaddr_in addr;
6637e3a5 596 socklen_t addr_len = 0;
76f87348 597 fde *F = &fd_table[fd];
090089c4 598
090089c4 599 /* If the fd is closed already, just return */
60c0b5a2 600 if (!F->flags.open) {
a3d5953d 601 debug(5, 0) ("comm_local_port: FD %d has been closed.\n", fd);
30a4f2a8 602 return 0;
090089c4 603 }
76f87348 604 if (F->local_port)
605 return F->local_port;
090089c4 606 addr_len = sizeof(addr);
607 if (getsockname(fd, (struct sockaddr *) &addr, &addr_len)) {
a3d5953d 608 debug(50, 1) ("comm_local_port: Failed to retrieve TCP/UDP port number for socket: FD %d: %s\n", fd, xstrerror());
30a4f2a8 609 return 0;
090089c4 610 }
76f87348 611 F->local_port = ntohs(addr.sin_port);
5f6ac48b 612 debug(5, 6) ("comm_local_port: FD %d: port %d\n", fd, (int) F->local_port);
76f87348 613 return F->local_port;
090089c4 614}
615
3d7e9d7c 616static comm_err_t
b8d8561b 617commBind(int s, struct in_addr in_addr, u_short port)
090089c4 618{
619 struct sockaddr_in S;
090089c4 620
090089c4 621 memset(&S, '\0', sizeof(S));
622 S.sin_family = AF_INET;
623 S.sin_port = htons(port);
30a4f2a8 624 S.sin_addr = in_addr;
83704487 625 statCounter.syscalls.sock.binds++;
090089c4 626 if (bind(s, (struct sockaddr *) &S, sizeof(S)) == 0)
627 return COMM_OK;
a3d5953d 628 debug(50, 0) ("commBind: Cannot bind socket FD %d to %s:%d: %s\n",
090089c4 629 s,
30a4f2a8 630 S.sin_addr.s_addr == INADDR_ANY ? "*" : inet_ntoa(S.sin_addr),
44a62238 631 (int) port,
632 xstrerror());
090089c4 633 return COMM_ERROR;
634}
635
636/* Create a socket. Default is blocking, stream (TCP) socket. IO_TYPE
d6827718 637 * is OR of flags specified in comm.h. Defaults TOS */
b8d8561b 638int
16b204c4 639comm_open(int sock_type,
cc6a9d2e 640 int proto,
641 struct in_addr addr,
642 u_short port,
643 int flags,
0ee4272b 644 const char *note)
d6827718 645{
646 return comm_openex(sock_type, proto, addr, port, flags, 0, note);
647}
648
649
650/* Create a socket. Default is blocking, stream (TCP) socket. IO_TYPE
651 * is OR of flags specified in defines.h:COMM_* */
652int
653comm_openex(int sock_type,
654 int proto,
655 struct in_addr addr,
656 u_short port,
657 int flags,
658 unsigned char TOS,
659 const char *note)
090089c4 660{
661 int new_socket;
9056f553 662 int tos = 0;
76f87348 663 fde *F = NULL;
090089c4 664
88bfe092 665 PROF_start(comm_open);
090089c4 666 /* Create socket for accepting new connections. */
83704487 667 statCounter.syscalls.sock.sockets++;
16b204c4 668 if ((new_socket = socket(AF_INET, sock_type, proto)) < 0) {
090089c4 669 /* Increase the number of reserved fd's if calls to socket()
670 * are failing because the open file table is full. This
671 * limits the number of simultaneous clients */
672 switch (errno) {
673 case ENFILE:
674 case EMFILE:
a3d5953d 675 debug(50, 1) ("comm_open: socket failure: %s\n", xstrerror());
9bc73deb 676 fdAdjustReserved();
090089c4 677 break;
678 default:
a3d5953d 679 debug(50, 0) ("comm_open: socket failure: %s\n", xstrerror());
090089c4 680 }
88bfe092 681 PROF_stop(comm_open);
603a02fd 682 return -1;
090089c4 683 }
d6827718 684 /* set TOS if needed */
685 if (TOS) {
686#ifdef IP_TOS
687 tos = TOS;
688 if (setsockopt(new_socket, IPPROTO_IP, IP_TOS, (char *) &tos, sizeof(int)) < 0)
689 debug(50, 1) ("comm_open: setsockopt(IP_TOS) on FD %d: %s\n",
690 new_socket, xstrerror());
691#else
692 debug(50, 0) ("comm_open: setsockopt(IP_TOS) not supported on this platform\n");
693#endif
694 }
090089c4 695 /* update fdstat */
365e5b34 696 debug(5, 5) ("comm_open: FD %d is a new socket\n", new_socket);
5c5783a2 697 fd_open(new_socket, FD_SOCKET, note);
c4b7a5a9 698 fdd_table[new_socket].close_file = NULL;
699 fdd_table[new_socket].close_line = 0;
700 assert(fdc_table[new_socket].active == 0);
701 fdc_table[new_socket].active = 1;
76f87348 702 F = &fd_table[new_socket];
d6827718 703 F->local_addr = addr;
704 F->tos = tos;
79a15e0a 705 if (!(flags & COMM_NOCLOEXEC))
3ca60c86 706 commSetCloseOnExec(new_socket);
cdc33f35 707 if ((flags & COMM_REUSEADDR))
708 commSetReuseAddr(new_socket);
7690e8eb 709 if (port > (u_short) 0) {
30a4f2a8 710 commSetNoLinger(new_socket);
3b4be6a6 711 if (opt_reuseaddr)
090089c4 712 commSetReuseAddr(new_socket);
090089c4 713 }
a3724d50 714 if (addr.s_addr != no_addr.s_addr) {
715 if (commBind(new_socket, addr, port) != COMM_OK) {
716 comm_close(new_socket);
603a02fd 717 return -1;
88bfe092 718 PROF_stop(comm_open);
a3724d50 719 }
23ff6968 720 }
76f87348 721 F->local_port = port;
090089c4 722
79a15e0a 723 if (flags & COMM_NONBLOCKING)
88bfe092 724 if (commSetNonBlocking(new_socket) == COMM_ERROR) {
603a02fd 725 return -1;
88bfe092 726 PROF_stop(comm_open);
727 }
30a4f2a8 728#ifdef TCP_NODELAY
729 if (sock_type == SOCK_STREAM)
730 commSetTcpNoDelay(new_socket);
731#endif
1241e63e 732 if (Config.tcpRcvBufsz > 0 && sock_type == SOCK_STREAM)
733 commSetTcpRcvbuf(new_socket, Config.tcpRcvBufsz);
88bfe092 734 PROF_stop(comm_open);
090089c4 735 return new_socket;
736}
737
e5f6c5c2 738void
4f92c80c 739commConnectStart(int fd, const char *host, u_short port, CNCB * callback, void *data)
e924600d 740{
28c60158 741 ConnectStateData *cs;
6a988308 742 debug(5, 3) ("commConnectStart: FD %d, %s:%d\n", fd, host, (int) port);
72711e31 743 cs = cbdataAlloc(ConnectStateData);
03a1ee42 744 cs->fd = fd;
e924600d 745 cs->host = xstrdup(host);
746 cs->port = port;
747 cs->callback = callback;
fa80a8ef 748 cs->data = cbdataReference(data);
e924600d 749 comm_add_close_handler(fd, commConnectFree, cs);
f88211e8 750 cs->locks++;
8407afee 751 ipcache_nbgethostbyname(host, commConnectDnsHandle, cs);
edeb28fd 752}
753
754static void
03a1ee42 755commConnectDnsHandle(const ipcache_addrs * ia, void *data)
edeb28fd 756{
e6ccf245 757 ConnectStateData *cs = (ConnectStateData *)data;
f88211e8 758 assert(cs->locks == 1);
759 cs->locks--;
edeb28fd 760 if (ia == NULL) {
a3d5953d 761 debug(5, 3) ("commConnectDnsHandle: Unknown host: %s\n", cs->host);
6cf028ab 762 if (!dns_error_message) {
763 dns_error_message = "Unknown DNS error";
0e473d70 764 debug(5, 1) ("commConnectDnsHandle: Bad dns_error_message\n");
6cf028ab 765 }
a64c2869 766 assert(dns_error_message != NULL);
03a1ee42 767 commConnectCallback(cs, COMM_ERR_DNS);
edeb28fd 768 return;
769 }
f076b37b 770 assert(ia->cur < ia->count);
edeb28fd 771 cs->in_addr = ia->in_addrs[ia->cur];
52926044 772 ipcacheCycleAddr(cs->host, NULL);
22c653cd 773 cs->addrcount = ia->count;
774 cs->connstart = squid_curtime;
03a1ee42 775 commConnectHandle(cs->fd, cs);
e924600d 776}
777
f88211e8 778static void
3d7e9d7c 779commConnectCallback(ConnectStateData * cs, comm_err_t status)
f88211e8 780{
a3d5953d 781 CNCB *callback = cs->callback;
fa80a8ef 782 void *cbdata = cs->data;
03a1ee42 783 int fd = cs->fd;
a3d5953d 784 comm_remove_close_handler(fd, commConnectFree, cs);
9daca08e 785 cs->callback = NULL;
786 cs->data = NULL;
e1b16349 787 commSetTimeout(fd, -1, NULL, NULL);
a3d5953d 788 commConnectFree(fd, cs);
fa80a8ef 789 if (cbdataReferenceValid(cbdata))
790 callback(fd, status, cbdata);
f88211e8 791}
792
e924600d 793static void
9daca08e 794commConnectFree(int fd, void *data)
e924600d 795{
e6ccf245 796 ConnectStateData *cs = (ConnectStateData *)data;
9daca08e 797 debug(5, 3) ("commConnectFree: FD %d\n", fd);
fa80a8ef 798 cbdataReferenceDone(cs->data);
8407afee 799 safe_free(cs->host);
800 cbdataFree(cs);
e924600d 801}
802
22c653cd 803/* Reset FD so that we can connect() again */
edeb28fd 804static int
22c653cd 805commResetFD(ConnectStateData * cs)
edeb28fd 806{
807 int fd2;
d6827718 808 fde *F;
fa80a8ef 809 if (!cbdataReferenceValid(cs->data))
7dd44885 810 return 0;
83704487 811 statCounter.syscalls.sock.sockets++;
edeb28fd 812 fd2 = socket(AF_INET, SOCK_STREAM, 0);
83704487 813 statCounter.syscalls.sock.sockets++;
edeb28fd 814 if (fd2 < 0) {
22c653cd 815 debug(5, 0) ("commResetFD: socket: %s\n", xstrerror());
9bc73deb 816 if (ENFILE == errno || EMFILE == errno)
817 fdAdjustReserved();
edeb28fd 818 return 0;
819 }
22c653cd 820 if (dup2(fd2, cs->fd) < 0) {
821 debug(5, 0) ("commResetFD: dup2: %s\n", xstrerror());
9bc73deb 822 if (ENFILE == errno || EMFILE == errno)
823 fdAdjustReserved();
d6827718 824 close(fd2);
edeb28fd 825 return 0;
826 }
edeb28fd 827 close(fd2);
d6827718 828 F = &fd_table[cs->fd];
b5568a61 829 fd_table[cs->fd].flags.called_connect = 0;
09544acc 830 /*
831 * yuck, this has assumptions about comm_open() arguments for
832 * the original socket
833 */
d6827718 834 if (commBind(cs->fd, F->local_addr, F->local_port) != COMM_OK) {
835 debug(5, 0) ("commResetFD: bind: %s\n", xstrerror());
836 return 0;
09544acc 837 }
d6827718 838#ifdef IP_TOS
839 if (F->tos) {
840 int tos = F->tos;
841 if (setsockopt(cs->fd, IPPROTO_IP, IP_TOS, (char *) &tos, sizeof(int)) < 0)
842 debug(50, 1) ("commResetFD: setsockopt(IP_TOS) on FD %d: %s\n", cs->fd, xstrerror());
843 }
844#endif
845 if (F->flags.close_on_exec)
846 commSetCloseOnExec(cs->fd);
847 if (F->flags.nonblocking)
848 commSetNonBlocking(cs->fd);
09544acc 849#ifdef TCP_NODELAY
d6827718 850 if (F->flags.nodelay)
851 commSetTcpNoDelay(cs->fd);
09544acc 852#endif
853 if (Config.tcpRcvBufsz > 0)
854 commSetTcpRcvbuf(cs->fd, Config.tcpRcvBufsz);
edeb28fd 855 return 1;
856}
857
22c653cd 858static int
859commRetryConnect(ConnectStateData * cs)
860{
861 assert(cs->addrcount > 0);
862 if (cs->addrcount == 1) {
863 if (cs->tries >= Config.retry.maxtries)
864 return 0;
865 if (squid_curtime - cs->connstart > Config.Timeout.connect)
866 return 0;
22c653cd 867 } else {
868 if (cs->tries > cs->addrcount)
869 return 0;
870 }
871 return commResetFD(cs);
872}
873
e924600d 874/* Connect SOCK to specified DEST_PORT at DEST_HOST. */
875static void
876commConnectHandle(int fd, void *data)
090089c4 877{
e6ccf245 878 ConnectStateData *cs = (ConnectStateData *)data;
f88211e8 879 if (cs->S.sin_addr.s_addr == 0) {
880 cs->S.sin_family = AF_INET;
881 cs->S.sin_addr = cs->in_addr;
882 cs->S.sin_port = htons(cs->port);
17a0a4ee 883 if (Config.onoff.log_fqdn)
f88211e8 884 fqdncache_gethostbyaddr(cs->S.sin_addr, FQDN_LOOKUP_IF_MISS);
e5f6c5c2 885 }
f88211e8 886 switch (comm_connect_addr(fd, &cs->S)) {
e5f6c5c2 887 case COMM_INPROGRESS:
11994bb9 888 debug(5, 5) ("commConnectHandle: FD %d: COMM_INPROGRESS\n", fd);
f88211e8 889 commSetSelect(fd, COMM_SELECT_WRITE, commConnectHandle, cs, 0);
e5f6c5c2 890 break;
891 case COMM_OK:
22c653cd 892 ipcacheMarkGoodAddr(cs->host, cs->S.sin_addr);
03a1ee42 893 commConnectCallback(cs, COMM_OK);
e5f6c5c2 894 break;
895 default:
22c653cd 896 cs->tries++;
897 ipcacheMarkBadAddr(cs->host, cs->S.sin_addr);
194dd3b8 898 if (Config.onoff.test_reachability)
899 netdbDeleteAddrNetwork(cs->S.sin_addr);
22c653cd 900 if (commRetryConnect(cs)) {
f88211e8 901 cs->locks++;
8407afee 902 ipcache_nbgethostbyname(cs->host, commConnectDnsHandle, cs);
edeb28fd 903 } else {
03a1ee42 904 commConnectCallback(cs, COMM_ERR_CONNECT);
edeb28fd 905 }
e5f6c5c2 906 break;
090089c4 907 }
090089c4 908}
22c653cd 909
b8d8561b 910int
4f92c80c 911commSetTimeout(int fd, int timeout, PF * handler, void *data)
090089c4 912{
76f87348 913 fde *F;
a3d5953d 914 debug(5, 3) ("commSetTimeout: FD %d timeout %d\n", fd, timeout);
03eb2f01 915 assert(fd >= 0);
916 assert(fd < Squid_MaxFD);
76f87348 917 F = &fd_table[fd];
60c0b5a2 918 assert(F->flags.open);
5c5783a2 919 if (timeout < 0) {
a3fa14bf 920 cbdataReferenceDone(F->timeout_data);
76f87348 921 F->timeout_handler = NULL;
a3fa14bf 922 F->timeout = 0;
5849612f 923 } else {
924 assert(handler || F->timeout_handler);
925 if (handler) {
926 cbdataReferenceDone(F->timeout_data);
927 F->timeout_handler = handler;
928 F->timeout_data = cbdataReference(data);
929 }
930 F->timeout = squid_curtime + (time_t) timeout;
30a4f2a8 931 }
a3fa14bf 932 return F->timeout;
090089c4 933}
934
b8d8561b 935int
0ee4272b 936comm_connect_addr(int sock, const struct sockaddr_in *address)
090089c4 937{
3d7e9d7c 938 comm_err_t status = COMM_OK;
76f87348 939 fde *F = &fd_table[sock];
090089c4 940 int x;
b5568a61 941 int err = 0;
9689d97c 942 socklen_t errlen;
489b22c1 943 assert(ntohs(address->sin_port) != 0);
88bfe092 944 PROF_start(comm_connect_addr);
090089c4 945 /* Establish connection. */
b5568a61 946 errno = 0;
947 if (!F->flags.called_connect) {
948 F->flags.called_connect = 1;
83704487 949 statCounter.syscalls.sock.connects++;
b5568a61 950 x = connect(sock, (struct sockaddr *) address, sizeof(*address));
54f742e7 951 if (x < 0)
952 debug(5, 9) ("connect FD %d: %s\n", sock, xstrerror());
b5568a61 953 } else {
140e2c0b 954#if defined(_SQUID_NEWSOS6_)
33ac9442 955 /* Makoto MATSUSHITA <matusita@ics.es.osaka-u.ac.jp> */
956 connect(sock, (struct sockaddr *) address, sizeof(*address));
957 if (errno == EINVAL) {
958 errlen = sizeof(err);
959 x = getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &errlen);
960 if (x >= 0)
961 errno = x;
962 }
963#else
b5568a61 964 errlen = sizeof(err);
965 x = getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &errlen);
966 if (x == 0)
967 errno = err;
968#if defined(_SQUID_SOLARIS_)
969 /*
970 * Solaris 2.4's socket emulation doesn't allow you
971 * to determine the error from a failed non-blocking
972 * connect and just returns EPIPE. Create a fake
973 * error message for connect. -- fenner@parc.xerox.com
974 */
975 if (x < 0 && errno == EPIPE)
976 errno = ENOTCONN;
33ac9442 977#endif
30a4f2a8 978#endif
e5f6c5c2 979 }
88bfe092 980 PROF_stop(comm_connect_addr);
b5568a61 981 if (errno == 0 || errno == EISCONN)
982 status = COMM_OK;
983 else if (ignoreErrno(errno))
984 status = COMM_INPROGRESS;
985 else
986 return COMM_ERROR;
76f87348 987 xstrncpy(F->ipaddr, inet_ntoa(address->sin_addr), 16);
988 F->remote_port = ntohs(address->sin_port);
090089c4 989 if (status == COMM_OK) {
a3d5953d 990 debug(5, 10) ("comm_connect_addr: FD %d connected to %s:%d\n",
76f87348 991 sock, F->ipaddr, F->remote_port);
f21cd581 992 } else if (status == COMM_INPROGRESS) {
a3d5953d 993 debug(5, 10) ("comm_connect_addr: FD %d connection pending\n", sock);
090089c4 994 }
090089c4 995 return status;
996}
997
998/* Wait for an incoming connection on FD. FD should be a socket returned
999 * from comm_listen. */
b8d8561b 1000int
c4b7a5a9 1001comm_old_accept(int fd, struct sockaddr_in *pn, struct sockaddr_in *me)
090089c4 1002{
1003 int sock;
1f9afe33 1004 struct sockaddr_in P;
1005 struct sockaddr_in M;
6637e3a5 1006 socklen_t Slen;
76f87348 1007 fde *F = NULL;
1f9afe33 1008 Slen = sizeof(P);
83704487 1009 statCounter.syscalls.sock.accepts++;
88bfe092 1010 PROF_start(comm_accept);
603500e7 1011 if ((sock = accept(fd, (struct sockaddr *) &P, &Slen)) < 0) {
88bfe092 1012 PROF_stop(comm_accept);
603500e7 1013 if (ignoreErrno(errno)) {
c4b7a5a9 1014 debug(50, 5) ("comm_old_accept: FD %d: %s\n", fd, xstrerror());
0a0bf5db 1015 return COMM_NOMESSAGE;
603500e7 1016 } else if (ENFILE == errno || EMFILE == errno) {
c4b7a5a9 1017 debug(50, 3) ("comm_old_accept: FD %d: %s\n", fd, xstrerror());
090089c4 1018 return COMM_ERROR;
603500e7 1019 } else {
c4b7a5a9 1020 debug(50, 1) ("comm_old_accept: FD %d: %s\n", fd, xstrerror());
090089c4 1021 return COMM_ERROR;
1022 }
1023 }
9ef28b60 1024 if (pn)
1025 *pn = P;
4053a845 1026 Slen = sizeof(M);
1027 memset(&M, '\0', Slen);
1028 getsockname(sock, (struct sockaddr *) &M, &Slen);
1029 if (me)
1f9afe33 1030 *me = M;
3ca60c86 1031 commSetCloseOnExec(sock);
090089c4 1032 /* fdstat update */
5c5783a2 1033 fd_open(sock, FD_SOCKET, "HTTP Request");
c4b7a5a9 1034 fdd_table[sock].close_file = NULL;
1035 fdd_table[sock].close_line = 0;
1036 fdc_table[sock].active = 1;
76f87348 1037 F = &fd_table[sock];
c0dec081 1038 xstrncpy(F->ipaddr, inet_ntoa(P.sin_addr), 16);
76f87348 1039 F->remote_port = htons(P.sin_port);
1040 F->local_port = htons(M.sin_port);
090089c4 1041 commSetNonBlocking(sock);
88bfe092 1042 PROF_stop(comm_accept);
090089c4 1043 return sock;
1044}
1045
cb201b7e 1046void
1047commCallCloseHandlers(int fd)
1048{
76f87348 1049 fde *F = &fd_table[fd];
f1dc9b30 1050 close_handler *ch;
a3d5953d 1051 debug(5, 5) ("commCallCloseHandlers: FD %d\n", fd);
29b8d8d6 1052 while ((ch = F->closeHandler) != NULL) {
1053 F->closeHandler = ch->next;
9daca08e 1054 debug(5, 5) ("commCallCloseHandlers: ch->handler=%p\n", ch->handler);
fa80a8ef 1055 if (cbdataReferenceValid(ch->data))
603a02fd 1056 ch->handler(fd, ch->data);
fa80a8ef 1057 cbdataReferenceDone(ch->data);
7f6ffd15 1058 memPoolFree(conn_close_pool, ch); /* AAA */
cb201b7e 1059 }
1060}
1061
5492ad1d 1062#if LINGERING_CLOSE
1063static void
1064commLingerClose(int fd, void *unused)
1065{
1066 LOCAL_ARRAY(char, buf, 1024);
1067 int n;
1f7c9178 1068 n = FD_READ_METHOD(fd, buf, 1024);
5492ad1d 1069 if (n < 0)
1070 debug(5, 3) ("commLingerClose: FD %d read: %s\n", fd, xstrerror());
1071 comm_close(fd);
1072}
1073
1074static void
1075commLingerTimeout(int fd, void *unused)
1076{
1077 debug(5, 3) ("commLingerTimeout: FD %d\n", fd);
1078 comm_close(fd);
1079}
1080
1081/*
1082 * Inspired by apache
1083 */
1084void
1085comm_lingering_close(int fd)
1086{
d4c19b39 1087#if USE_SSL
1088 if (fd_table[fd].ssl)
79d4ccdf 1089 ssl_shutdown_method(fd);
d4c19b39 1090#endif
5492ad1d 1091 if (shutdown(fd, 1) < 0) {
1092 comm_close(fd);
1093 return;
1094 }
1095 fd_note(fd, "lingering close");
1096 commSetTimeout(fd, 10, commLingerTimeout, NULL);
1097 commSetSelect(fd, COMM_SELECT_READ, commLingerClose, NULL, 0);
1098}
1099#endif
1100
98264874 1101/*
1102 * enable linger with time of 0 so that when the socket is
1103 * closed, TCP generates a RESET
1104 */
1105void
1106comm_reset_close(int fd)
1107{
1108 struct linger L;
1109 L.l_onoff = 1;
1110 L.l_linger = 0;
1111 if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &L, sizeof(L)) < 0)
1112 debug(50, 0) ("commResetTCPClose: FD %d: %s\n", fd, xstrerror());
1113 comm_close(fd);
1114}
1115
c4b7a5a9 1116
1117/*
1118 * Close the socket fd.
1119 *
1120 * + call write handlers with ERR_CLOSING
1121 * + call read handlers with ERR_CLOSING
1122 * + call closing handlers
1123 */
b8d8561b 1124void
c4b7a5a9 1125_comm_close(int fd, char *file, int line)
090089c4 1126{
76f87348 1127 fde *F = NULL;
c4b7a5a9 1128 dlink_node *node;
1129 CommCallbackData *cio;
1f7c9178 1130
a3d5953d 1131 debug(5, 5) ("comm_close: FD %d\n", fd);
03eb2f01 1132 assert(fd >= 0);
1133 assert(fd < Squid_MaxFD);
76f87348 1134 F = &fd_table[fd];
c4b7a5a9 1135 fdd_table[fd].close_file = file;
1136 fdd_table[fd].close_line = line;
1f7c9178 1137
58a6c186 1138 if (F->flags.closing)
e102ebda 1139 return;
60c0b5a2 1140 if (shutting_down && (!F->flags.open || F->type == FD_FILE))
6cf028ab 1141 return;
60c0b5a2 1142 assert(F->flags.open);
c4b7a5a9 1143 /* The following fails because ipc.c is doing calls to pipe() to create sockets! */
1144 /* assert(fdc_table[fd].active == 1); */
76f87348 1145 assert(F->type != FD_FILE);
88bfe092 1146 PROF_start(comm_close);
58a6c186 1147 F->flags.closing = 1;
d4c19b39 1148#if USE_SSL
1149 if (F->ssl)
79d4ccdf 1150 ssl_shutdown_method(fd);
d4c19b39 1151#endif
fa80a8ef 1152 commSetTimeout(fd, -1, NULL, NULL);
96f1be5d 1153 CommWriteStateCallbackAndFree(fd, COMM_ERR_CLOSING);
c4b7a5a9 1154
691476e2 1155 /* Do callbacks for read/accept/fill routines, if any */
511e2383 1156 if (fdc_table[fd].read.handler) {
691476e2 1157 fdc_table[fd].read.handler(fd, fdc_table[fd].read.buf, 0,
1158 COMM_ERR_CLOSING, 0, fdc_table[fd].read.handler_data);
511e2383 1159 fdc_table[fd].read.handler = NULL;
1160 }
1161 if (fdc_table[fd].accept.handler) {
691476e2 1162 fdc_table[fd].accept.handler(fd, -1, NULL, NULL, COMM_ERR_CLOSING,
1163 0, fdc_table[fd].accept.handler_data);
511e2383 1164 fdc_table[fd].accept.handler = NULL;
1165 }
1166 if (fdc_table[fd].fill.handler) {
691476e2 1167 fdc_table[fd].fill.handler(fd, fdc_table[fd].fill.requestedData, COMM_ERR_CLOSING, 0,
1168 fdc_table[fd].fill.handler_data);
511e2383 1169 fdc_table[fd].fill.handler = NULL;
1170 }
1171 /* Complete (w/ COMM_ERR_CLOSING!) any pending io callbacks */
c4b7a5a9 1172 while (fdc_table[fd].CommCallbackList.head != NULL) {
1173 node = fdc_table[fd].CommCallbackList.head;
1174 cio = (CommCallbackData *)node->data;
1175 assert(fd == cio->fd); /* just paranoid */
1176 dlinkDelete(&cio->h_node, &CommCallbackList);
1177 dlinkDelete(&cio->fd_node, &(fdc_table[cio->fd].CommCallbackList));
504cd889 1178 /* We're closing! */
1179 cio->errcode = COMM_ERR_CLOSING;
c4b7a5a9 1180 comm_call_io_callback(cio);
1181 memPoolFree(comm_callback_pool, cio);
1182 }
1183
511e2383 1184
cb201b7e 1185 commCallCloseHandlers(fd);
b716a8ad 1186 if (F->uses) /* assume persistent connect count */
1187 pconnHistCount(1, F->uses);
d4c19b39 1188#if USE_SSL
1189 if (F->ssl) {
1190 SSL_free(F->ssl);
1191 F->ssl = NULL;
1192 }
1193#endif
c4b7a5a9 1194 comm_empty_os_read_buffers(fd);
5c5783a2 1195 fd_close(fd); /* update fdstat */
5874bf28 1196 close(fd);
c4b7a5a9 1197 fdc_table[fd].active = 0;
1198 bzero(&fdc_table[fd], sizeof(fdc_t));
83704487 1199 statCounter.syscalls.sock.closes++;
88bfe092 1200 PROF_stop(comm_close);
090089c4 1201}
1202
090089c4 1203/* Send a udp datagram to specified TO_ADDR. */
b8d8561b 1204int
5df61230 1205comm_udp_sendto(int fd,
1206 const struct sockaddr_in *to_addr,
1207 int addr_len,
17b6e784 1208 const void *buf,
5df61230 1209 int len)
090089c4 1210{
5df61230 1211 int x;
88bfe092 1212 PROF_start(comm_udp_sendto);
83704487 1213 statCounter.syscalls.sock.sendtos++;
5df61230 1214 x = sendto(fd, buf, len, 0, (struct sockaddr *) to_addr, addr_len);
88bfe092 1215 PROF_stop(comm_udp_sendto);
5df61230 1216 if (x < 0) {
17d51783 1217#ifdef _SQUID_LINUX_
1218 if (ECONNREFUSED != errno)
1219#endif
1220 debug(50, 1) ("comm_udp_sendto: FD %d, %s, port %d: %s\n",
1221 fd,
1222 inet_ntoa(to_addr->sin_addr),
1223 (int) htons(to_addr->sin_port),
1224 xstrerror());
090089c4 1225 return COMM_ERROR;
1226 }
5df61230 1227 return x;
090089c4 1228}
1229
b8d8561b 1230void
70a9dab4 1231commSetDefer(int fd, DEFER * func, void *data)
4883993a 1232{
da2b3a17 1233 fde *F = &fd_table[fd];
1234 F->defer_check = func;
70a9dab4 1235 F->defer_data = data;
4883993a 1236}
1237
b8d8561b 1238void
582b6456 1239comm_add_close_handler(int fd, PF * handler, void *data)
30a4f2a8 1240{
e6ccf245 1241 close_handler *newHandler = (close_handler *)memPoolAlloc(conn_close_pool); /* AAA */
cddc721b 1242 close_handler *c;
a3d5953d 1243 debug(5, 5) ("comm_add_close_handler: FD %d, handler=%p, data=%p\n",
e0c42e90 1244 fd, handler, data);
29b8d8d6 1245 for (c = fd_table[fd].closeHandler; c; c = c->next)
aeca2a09 1246 assert(c->handler != handler || c->data != data);
e6ccf245 1247 newHandler->handler = handler;
1248 newHandler->data = cbdataReference(data);
1249 newHandler->next = fd_table[fd].closeHandler;
1250 fd_table[fd].closeHandler = newHandler;
30a4f2a8 1251}
1252
b8d8561b 1253void
582b6456 1254comm_remove_close_handler(int fd, PF * handler, void *data)
090089c4 1255{
f1dc9b30 1256 close_handler *p;
1257 close_handler *last = NULL;
30a4f2a8 1258 /* Find handler in list */
e869f2bd 1259 debug(5, 5) ("comm_remove_close_handler: FD %d, handler=%p, data=%p\n",
1260 fd, handler, data);
29b8d8d6 1261 for (p = fd_table[fd].closeHandler; p != NULL; last = p, p = p->next)
30a4f2a8 1262 if (p->handler == handler && p->data == data)
1263 break; /* This is our handler */
f88211e8 1264 assert(p != NULL);
30a4f2a8 1265 /* Remove list entry */
1266 if (last)
1267 last->next = p->next;
1268 else
29b8d8d6 1269 fd_table[fd].closeHandler = p->next;
fa80a8ef 1270 cbdataReferenceDone(p->data);
1271 memPoolFree(conn_close_pool, p);
30a4f2a8 1272}
090089c4 1273
b8d8561b 1274static void
1275commSetNoLinger(int fd)
30a4f2a8 1276{
1277 struct linger L;
090089c4 1278 L.l_onoff = 0; /* off */
1279 L.l_linger = 0;
30a4f2a8 1280 if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &L, sizeof(L)) < 0)
a3d5953d 1281 debug(50, 0) ("commSetNoLinger: FD %d: %s\n", fd, xstrerror());
58a6c186 1282 fd_table[fd].flags.nolinger = 1;
090089c4 1283}
1284
b8d8561b 1285static void
1286commSetReuseAddr(int fd)
090089c4 1287{
1288 int on = 1;
30a4f2a8 1289 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0)
a3d5953d 1290 debug(50, 1) ("commSetReuseAddr: FD %d: %s\n", fd, xstrerror());
090089c4 1291}
1292
b8d8561b 1293static void
1294commSetTcpRcvbuf(int fd, int size)
f868539a 1295{
1296 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *) &size, sizeof(size)) < 0)
a3d5953d 1297 debug(50, 1) ("commSetTcpRcvbuf: FD %d, SIZE %d: %s\n",
b6f794d6 1298 fd, size, xstrerror());
f868539a 1299}
1300
b8d8561b 1301int
1302commSetNonBlocking(int fd)
30a4f2a8 1303{
731e4d49 1304 int flags;
9e205701 1305 int dummy = 0;
7f6ffd15 1306#ifdef _SQUID_CYGWIN_
b05490a8 1307 int nonblocking = TRUE;
7f6ffd15 1308 if (fd_table[fd].type != FD_PIPE) {
1309 if (ioctl(fd, FIONBIO, &nonblocking) < 0) {
c4b7a5a9 1310 debug(50, 0) ("commSetNonBlocking: FD %d: %s %D\n", fd, xstrerror(), fd_table[fd].type);
7f6ffd15 1311 return COMM_ERROR;
1312 }
1313 } else {
1314#endif
1315 if ((flags = fcntl(fd, F_GETFL, dummy)) < 0) {
1316 debug(50, 0) ("FD %d: fcntl F_GETFL: %s\n", fd, xstrerror());
1317 return COMM_ERROR;
1318 }
1319 if (fcntl(fd, F_SETFL, flags | SQUID_NONBLOCK) < 0) {
1320 debug(50, 0) ("commSetNonBlocking: FD %d: %s\n", fd, xstrerror());
1321 return COMM_ERROR;
1322 }
1323#ifdef _SQUID_CYGWIN_
090089c4 1324 }
7f6ffd15 1325#endif
58a6c186 1326 fd_table[fd].flags.nonblocking = 1;
090089c4 1327 return 0;
1328}
1329
7e3ce7b9 1330int
1331commUnsetNonBlocking(int fd)
1332{
1333 int flags;
1334 int dummy = 0;
1335 if ((flags = fcntl(fd, F_GETFL, dummy)) < 0) {
1336 debug(50, 0) ("FD %d: fcntl F_GETFL: %s\n", fd, xstrerror());
1337 return COMM_ERROR;
1338 }
1339 if (fcntl(fd, F_SETFL, flags & (~SQUID_NONBLOCK)) < 0) {
1340 debug(50, 0) ("commUnsetNonBlocking: FD %d: %s\n", fd, xstrerror());
1341 return COMM_ERROR;
1342 }
1343 fd_table[fd].flags.nonblocking = 0;
1344 return 0;
1345}
1346
b8d8561b 1347void
1348commSetCloseOnExec(int fd)
3ca60c86 1349{
1350#ifdef FD_CLOEXEC
731e4d49 1351 int flags;
7a18b487 1352 int dummy = 0;
c7989865 1353 if ((flags = fcntl(fd, F_GETFL, dummy)) < 0) {
a3d5953d 1354 debug(50, 0) ("FD %d: fcntl F_GETFL: %s\n", fd, xstrerror());
24382924 1355 return;
3ca60c86 1356 }
24382924 1357 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
a3d5953d 1358 debug(50, 0) ("FD %d: set close-on-exec failed: %s\n", fd, xstrerror());
d6827718 1359 fd_table[fd].flags.close_on_exec = 1;
3ca60c86 1360#endif
1361}
1362
e90100aa 1363#ifdef TCP_NODELAY
1364static void
1365commSetTcpNoDelay(int fd)
1366{
1367 int on = 1;
1368 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on)) < 0)
a3d5953d 1369 debug(50, 1) ("commSetTcpNoDelay: FD %d: %s\n", fd, xstrerror());
d6827718 1370 fd_table[fd].flags.nodelay = 1;
e90100aa 1371}
1372#endif
1373
6a988308 1374
d86b3703 1375void
0673c0ba 1376comm_init(void)
090089c4 1377{
c4b7a5a9 1378 fd_table =(fde *) xcalloc(Squid_MaxFD, sizeof(fde));
1379 fdd_table = (fd_debug_t *)xcalloc(Squid_MaxFD, sizeof(fd_debug_t));
1380 fdc_table = (fdc_t *)xcalloc(Squid_MaxFD, sizeof(fdc_t));
59c4d35b 1381 /* XXX account fd_table */
090089c4 1382 /* Keep a few file descriptors free so that we don't run out of FD's
1383 * after accepting a client but before it opens a socket or a file.
e83892e9 1384 * Since Squid_MaxFD can be as high as several thousand, don't waste them */
0254ee29 1385 RESERVED_FD = XMIN(100, Squid_MaxFD / 4);
28c60158 1386 CBDATA_INIT_TYPE(ConnectStateData);
c4b7a5a9 1387
1388 comm_callback_pool = memPoolCreate("comm callbacks", sizeof(CommCallbackData));
723123a9 1389 comm_write_pool = memPoolCreate("CommWriteStateData", sizeof(CommWriteStateData));
58cd5bbd 1390 conn_close_pool = memPoolCreate("close_handler", sizeof(close_handler));
090089c4 1391}
1392
30a4f2a8 1393/* Write to FD. */
b8d8561b 1394static void
582b6456 1395commHandleWrite(int fd, void *data)
30a4f2a8 1396{
e6ccf245 1397 CommWriteStateData *state = (CommWriteStateData *)data;
30a4f2a8 1398 int len = 0;
1399 int nleft;
1400
88bfe092 1401 PROF_start(commHandleWrite);
32754419 1402 debug(5, 5) ("commHandleWrite: FD %d: off %ld, sz %ld.\n",
1403 fd, (long int) state->offset, (long int) state->size);
30a4f2a8 1404
1405 nleft = state->size - state->offset;
1f7c9178 1406 len = FD_WRITE_METHOD(fd, state->buf + state->offset, nleft);
6a988308 1407 debug(5, 5) ("commHandleWrite: write() returns %d\n", len);
b69f7771 1408 fd_bytes(fd, len, FD_WRITE);
83704487 1409 statCounter.syscalls.sock.writes++;
30a4f2a8 1410
1411 if (len == 0) {
1412 /* Note we even call write if nleft == 0 */
1413 /* We're done */
1414 if (nleft != 0)
02be0294 1415 debug(5, 1) ("commHandleWrite: FD %d: write failure: connection closed with %d bytes remaining.\n", fd, nleft);
f17936ab 1416 CommWriteStateCallbackAndFree(fd, nleft ? COMM_ERROR : COMM_OK);
30a4f2a8 1417 } else if (len < 0) {
1418 /* An error */
e8d6569c 1419 if (fd_table[fd].flags.socket_eof) {
1420 debug(50, 2) ("commHandleWrite: FD %d: write failure: %s.\n",
1421 fd, xstrerror());
1422 CommWriteStateCallbackAndFree(fd, COMM_ERROR);
1423 } else if (ignoreErrno(errno)) {
a3d5953d 1424 debug(50, 10) ("commHandleWrite: FD %d: write failure: %s.\n",
30a4f2a8 1425 fd, xstrerror());
b177367b 1426 commSetSelect(fd,
30a4f2a8 1427 COMM_SELECT_WRITE,
cd1fb0eb 1428 commHandleWrite,
b177367b 1429 state,
85d7ea98 1430 0);
9864ee44 1431 } else {
a3d5953d 1432 debug(50, 2) ("commHandleWrite: FD %d: write failure: %s.\n",
9864ee44 1433 fd, xstrerror());
f17936ab 1434 CommWriteStateCallbackAndFree(fd, COMM_ERROR);
30a4f2a8 1435 }
30a4f2a8 1436 } else {
1437 /* A successful write, continue */
1438 state->offset += len;
e6ccf245 1439 if (state->offset < (off_t)state->size) {
30a4f2a8 1440 /* Not done, reinstall the write handler and write some more */
b177367b 1441 commSetSelect(fd,
30a4f2a8 1442 COMM_SELECT_WRITE,
cd1fb0eb 1443 commHandleWrite,
b177367b 1444 state,
85d7ea98 1445 0);
9864ee44 1446 } else {
f17936ab 1447 CommWriteStateCallbackAndFree(fd, COMM_OK);
30a4f2a8 1448 }
30a4f2a8 1449 }
88bfe092 1450 PROF_stop(commHandleWrite);
30a4f2a8 1451}
1452
1453
1454
7cd8c414 1455/*
1456 * Queue a write. handler/handler_data are called when the write
1457 * completes, on error, or on file descriptor close.
1458 *
1459 * free_func is used to free the passed buffer when the write has completed.
1460 */
b8d8561b 1461void
a2c963ae 1462comm_write(int fd, const char *buf, int size, CWCB * handler, void *handler_data, FREE * free_func)
30a4f2a8 1463{
aa9e2cab 1464 CommWriteStateData *state = fd_table[fd].rwstate;
c4b7a5a9 1465
1466 assert(!fd_table[fd].flags.closing);
1467
a3d5953d 1468 debug(5, 5) ("comm_write: FD %d: sz %d: hndl %p: data %p.\n",
787869c5 1469 fd, size, handler, handler_data);
aa9e2cab 1470 if (NULL != state) {
afde8a9d 1471 debug(5, 1) ("comm_write: fd_table[%d].rwstate != NULL\n", fd);
723123a9 1472 memPoolFree(comm_write_pool, state);
6cf028ab 1473 fd_table[fd].rwstate = NULL;
1474 }
e6ccf245 1475 fd_table[fd].rwstate = state = (CommWriteStateData *)memPoolAlloc(comm_write_pool);
a2c963ae 1476 state->buf = (char *) buf;
30a4f2a8 1477 state->size = size;
1478 state->offset = 0;
1479 state->handler = handler;
fa80a8ef 1480 state->handler_data = cbdataReference(handler_data);
c0dec081 1481 state->free_func = free_func;
aa9e2cab 1482 commSetSelect(fd, COMM_SELECT_WRITE, commHandleWrite, state, 0);
30a4f2a8 1483}
26a880e2 1484
137ee196 1485/* a wrapper around comm_write to allow for MemBuf to be comm_written in a snap */
cb69b4c7 1486void
1487comm_write_mbuf(int fd, MemBuf mb, CWCB * handler, void *handler_data)
1488{
1489 comm_write(fd, mb.buf, mb.size, handler, handler_data, memBufFreeFunc(&mb));
1490}
1491
c4b7a5a9 1492
89924214 1493/*
1494 * hm, this might be too general-purpose for all the places we'd
1495 * like to use it.
1496 */
b224ea98 1497int
edd2eb63 1498ignoreErrno(int ierrno)
26a880e2 1499{
603500e7 1500 switch (ierrno) {
89924214 1501 case EINPROGRESS:
603500e7 1502 case EWOULDBLOCK:
26a880e2 1503#if EAGAIN != EWOULDBLOCK
603500e7 1504 case EAGAIN:
26a880e2 1505#endif
603500e7 1506 case EALREADY:
1507 case EINTR:
db494ab8 1508#ifdef ERESTART
1509 case ERESTART:
1510#endif
26a880e2 1511 return 1;
603500e7 1512 default:
1513 return 0;
1514 }
1515 /* NOTREACHED */
26a880e2 1516}
d723bf6b 1517
1518void
1519commCloseAllSockets(void)
1520{
1521 int fd;
1522 fde *F = NULL;
d723bf6b 1523 for (fd = 0; fd <= Biggest_FD; fd++) {
1524 F = &fd_table[fd];
60c0b5a2 1525 if (!F->flags.open)
d723bf6b 1526 continue;
1527 if (F->type != FD_SOCKET)
1528 continue;
de718ec4 1529 if (F->flags.ipc) /* don't close inter-process sockets */
1530 continue;
d723bf6b 1531 if (F->timeout_handler) {
fa80a8ef 1532 PF *callback = F->timeout_handler;
1533 void *cbdata = NULL;
1534 F->timeout_handler = NULL;
d723bf6b 1535 debug(5, 5) ("commCloseAllSockets: FD %d: Calling timeout handler\n",
1536 fd);
fa80a8ef 1537 if (cbdataReferenceValidDone(F->timeout_data, &cbdata))
1538 callback(fd, cbdata);
d723bf6b 1539 } else {
1540 debug(5, 5) ("commCloseAllSockets: FD %d: calling comm_close()\n", fd);
1541 comm_close(fd);
1542 }
1543 }
1544}
1b3db6d9 1545
1546void
1547checkTimeouts(void)
1548{
1549 int fd;
1550 fde *F = NULL;
1551 PF *callback;
1552 for (fd = 0; fd <= Biggest_FD; fd++) {
b5443c04 1553 F = &fd_table[fd];
1554 if (!F->flags.open)
1555 continue;
1556 if (F->timeout == 0)
1557 continue;
1558 if (F->timeout > squid_curtime)
1559 continue;
1560 debug(5, 5) ("checkTimeouts: FD %d Expired\n", fd);
1561 if (F->timeout_handler) {
1562 debug(5, 5) ("checkTimeouts: FD %d: Call timeout handler\n", fd);
1563 callback = F->timeout_handler;
1564 F->timeout_handler = NULL;
1565 callback(fd, F->timeout_data);
1566 } else {
1567 debug(5, 5) ("checkTimeouts: FD %d: Forcing comm_close()\n", fd);
1568 comm_close(fd);
1569 }
1570 }
1571}
1572
1573
1574int
1b3db6d9 1575commDeferRead(int fd)
1576{
1577 fde *F = &fd_table[fd];
1578 if (F->defer_check == NULL)
b5443c04 1579 return 0;
1b3db6d9 1580 return F->defer_check(fd, F->defer_data);
1581}
c4b7a5a9 1582
1583
1584/*
1585 * New-style listen and accept routines
1586 *
1587 * Listen simply registers our interest in an FD for listening,
1588 * and accept takes a callback to call when an FD has been
1589 * accept()ed.
1590 */
1591int
1592comm_listen(int sock)
1593{
1594 int x;
1595 if ((x = listen(sock, Squid_MaxFD >> 2)) < 0) {
1596 debug(50, 0) ("comm_listen: listen(%d, %d): %s\n",
1597 Squid_MaxFD >> 2,
1598 sock, xstrerror());
1599 return x;
1600 }
1601 return sock;
1602}
1603
1604
1605/*
1606 * This callback is called whenever a filedescriptor is ready
1607 * to dupe itself and fob off an accept()ed connection
1608 */
1609static void
1610comm_accept_try(int fd, void *data)
1611{
1612 int newfd;
1613 fdc_t *Fc;
1614
1615 assert(fdc_table[fd].active == 1);
1616
1617 Fc = &(fdc_table[fd]);
1618
1619 /* Accept a new connection */
1620 newfd = comm_old_accept(fd, &Fc->accept.pn, &Fc->accept.me);
1621
1622 if (newfd < 0) {
1623 /* Issues - check them */
1624 if (newfd == COMM_NOMESSAGE) {
1625 /* register interest again */
1626 commSetSelect(fd, COMM_SELECT_READ, comm_accept_try, NULL, 0);
1627 return;
1628 }
1629 /* Problem! */
1630 comm_addacceptcallback(fd, -1, Fc->accept.handler, &Fc->accept.pn, &Fc->accept.me, COMM_ERROR, errno, Fc->accept.handler_data);
1631 Fc->accept.handler = NULL;
1632 Fc->accept.handler_data = NULL;
1633 return;
1634 }
1635
1636 /* setup our new filedescriptor in fd_table */
1637 /* and set it up in fdc_table */
1638
1639 /* queue a completed callback with the new FD */
1640 comm_addacceptcallback(fd, newfd, Fc->accept.handler, &Fc->accept.pn, &Fc->accept.me, COMM_OK, 0, Fc->accept.handler_data);
1641 Fc->accept.handler = NULL;
1642 Fc->accept.handler_data = NULL;
1643
1644}
1645
1646
1647/*
1648 * Notes:
1649 * + the current interface will queue _one_ accept per io loop.
1650 * this isn't very optimal and should be revisited at a later date.
1651 */
1652void
1653comm_accept(int fd, IOACB *handler, void *handler_data)
1654{
1655 fdc_t *Fc;
1656
1657 assert(fd_table[fd].flags.open == 1);
1658 assert(fdc_table[fd].active == 1);
1659
1660 /* make sure we're not pending! */
1661 assert(fdc_table[fd].accept.handler == NULL);
1662
1663 /* Record our details */
1664 Fc = &fdc_table[fd];
1665 Fc->accept.handler = handler;
1666 Fc->accept.handler_data = handler_data;
1667
1668 /* Kick off the accept */
1669#if OPTIMISTIC_IO
1670 comm_accept_try(fd, NULL);
1671#else
1672 commSetSelect(fd, COMM_SELECT_READ, comm_accept_try, NULL, 0);
1673#endif
1674}