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