]> git.ipfire.org Git - thirdparty/squid.git/blame - src/comm.cc
Summary: Add squid-3.0 release notes.
[thirdparty/squid.git] / src / comm.cc
CommitLineData
da2b3a17 1
30a4f2a8 2/*
43ae1d95 3 * $Id: comm.cc,v 1.372 2003/03/10 04:56:37 robertc 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 *
2d8c0b1a 34 *
35 * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
30a4f2a8 36 */
090089c4 37
44a47c6e 38#include "squid.h"
c4b7a5a9 39#include "StoreIOBuffer.h"
40#include "comm.h"
528b2c61 41#include "fde.h"
ee0989f2 42#include "ConnectionDetail.h"
090089c4 43
b671cc68 44#if defined(_SQUID_CYGWIN_)
45#include <sys/ioctl.h>
46#endif
30a4f2a8 47#ifdef HAVE_NETINET_TCP_H
48#include <netinet/tcp.h>
49#endif
090089c4 50
f49a8979 51
2d8c0b1a 52class ConnectStateData
62e76326 53{
2d8c0b1a 54
55public:
56 static void Connect (int fd, void *me);
57 void connect();
58 void callCallback(comm_err_t status, int xerrno);
59 void defaults();
f88211e8 60 char *host;
61 u_short port;
62e76326 62
f88211e8 63 struct sockaddr_in S;
2d8c0b1a 64 CallBack<CNCB> callback;
62e76326 65
f88211e8 66 struct in_addr in_addr;
67 int locks;
03a1ee42 68 int fd;
22c653cd 69 int tries;
70 int addrcount;
71 int connstart;
2d8c0b1a 72};
f88211e8 73
090089c4 74/* STATIC */
62e76326 75
e6ccf245 76static comm_err_t commBind(int s, struct in_addr, u_short port);
f5b8bbc4 77static void commSetReuseAddr(int);
78static void commSetNoLinger(int);
3d7e9d7c 79static void CommWriteStateCallbackAndFree(int fd, comm_err_t code);
30a4f2a8 80#ifdef TCP_NODELAY
f5b8bbc4 81static void commSetTcpNoDelay(int);
30a4f2a8 82#endif
f5b8bbc4 83static void commSetTcpRcvbuf(int, int);
f88211e8 84static PF commConnectFree;
03a1ee42 85static PF commHandleWrite;
edeb28fd 86static IPH commConnectDnsHandle;
22c653cd 87static int commResetFD(ConnectStateData * cs);
88static int commRetryConnect(ConnectStateData * cs);
28c60158 89CBDATA_TYPE(ConnectStateData);
723123a9 90
3c1a197f 91static PF comm_accept_try;
c4b7a5a9 92
62e76326 93class AcceptFD
94{
95
96public:
2d8c0b1a 97 AcceptFD() : check_delay(0), count(0), finished_(false){}
98
99 void doCallback(int fd, int newfd, comm_err_t errcode, int xerrno, ConnectionDetail *);
100 void nullCallback();
101 void beginAccepting() {count = 0; finished(false);}
102
103 size_t acceptCount() const { return count;}
104
105 bool finishedAccepting() const;
ee0989f2 106 int check_delay;
2d8c0b1a 107 CallBack<IOACB> callback;
108 bool finished() const;
109 void finished(bool);
110
111private:
112 static size_t const MAX_ACCEPT_PER_LOOP = 10;
113 size_t count;
114 bool finished_;
115};
116
117class CommWrite
118{
119
120public:
121 CommWrite() : buf(NULL), size(0), curofs(0), handler(NULL), handler_data(NULL){}
122
123 const char *buf;
124 int size;
125 int curofs;
126 IOCB *handler;
ee0989f2 127 void *handler_data;
128};
129
a46d2c0e 130class fdc_t
62e76326 131{
a46d2c0e 132
133public:
2d8c0b1a 134 void acceptOne(int fd);
135 void beginAccepting();
136 int acceptCount() const;
137 fdc_t() : active(0), fd(-1), half_closed (false){CommCallbackList.head = NULL;CommCallbackList.tail = NULL; fill.amountDone = 0; fill.handler = NULL; fill.handler_data = NULL;}
62e76326 138
2d8c0b1a 139 fdc_t(int anFD) : active(0), fd(anFD), half_closed(false)
62e76326 140 {
2d8c0b1a 141 CommCallbackList.head = NULL;
142 CommCallbackList.tail = NULL;
143 fill.amountDone = 0;
144 fill.handler = NULL;
145 fill.handler_data = NULL;
146 read.fd = anFD;
62e76326 147 }
148
2d8c0b1a 149 int active;
150 int fd;
151 dlink_list CommCallbackList;
62e76326 152
2d8c0b1a 153 CommRead read;
62e76326 154
2d8c0b1a 155 CommWrite write;
62e76326 156
157 struct
158 {
159 /* how often (in msec) to re-check if we're out of fds on an accept() */
62e76326 160 AcceptFD accept;
161 ConnectionDetail connDetails;
162 }
163
164 accept;
165
166 struct CommFiller
167 {
168 StoreIOBuffer requestedData;
169 size_t amountDone;
170 IOFCB *handler;
171 void *handler_data;
172 }
173
174 fill;
c4b7a5a9 175
a46d2c0e 176 bool half_closed;
c4b7a5a9 177};
62e76326 178
c4b7a5a9 179typedef enum {
62e76326 180 COMM_CB_READ = 1,
2d8c0b1a 181 COMM_CB_DERIVED,
c4b7a5a9 182} comm_callback_t;
183
2d8c0b1a 184static int CommCallbackSeqnum = 1;
185
186class CommCommonCallback
62e76326 187{
2d8c0b1a 188
189public:
190 CommCommonCallback() : fd (-1), errcode (COMM_OK), xerrno(0), seqnum (CommCallbackSeqnum){}
191
192 CommCommonCallback(int anFD, comm_err_t errcode, int anErrno) : fd (anFD), errcode (errcode), xerrno(anErrno), seqnum (CommCallbackSeqnum){}
193
62e76326 194 int fd;
62e76326 195 comm_err_t errcode;
196 int xerrno;
197 int seqnum;
2d8c0b1a 198};
199
200class CommCallbackData
201{
202
203public:
204 void *operator new(size_t);
205 void operator delete(void *);
206 virtual void deleteSelf() const;
207 CommCallbackData(CommCommonCallback const &);
208 virtual comm_callback_t getType() const { return COMM_CB_DERIVED; }
209
210 void callACallback();
211 void fdClosing();
212 virtual void callCallback() = 0;
213 void registerSelf();
214 void deRegisterSelf();
215 char *buf;
62e76326 216 StoreIOBuffer sb;
2d8c0b1a 217
218protected:
219 CommCommonCallback result;
43ae1d95 220 friend void _comm_close(int fd, char const *file, int line);
2d8c0b1a 221 friend void comm_calliocallback(void);
222
223private:
224 static MemPool *Pool;
225 dlink_node fd_node;
226 dlink_node h_node;
c4b7a5a9 227};
62e76326 228
2d8c0b1a 229class CommReadCallbackData : public CommCallbackData
230{
231
232public:
233 void *operator new(size_t);
234 void operator delete(void *);
235 void deleteSelf() const;
236 CommReadCallbackData(CommCommonCallback const &, CallBack<IOCB> aCallback, int);
237 virtual comm_callback_t getType() const { return COMM_CB_READ; }
238
239 virtual void callCallback();
240
241private:
242 static MemPool *Pool;
243 CallBack<IOCB> callback;
244 int retval;
245};
246
247class CommAcceptCallbackData : public CommCallbackData
248{
249
250public:
251 void *operator new(size_t);
252 void operator delete(void *);
253 void deleteSelf() const;
254 CommAcceptCallbackData(int const anFd, CallBack<IOACB>, comm_err_t, int, int, ConnectionDetail const &);
255 virtual void callCallback();
256
257private:
258 static MemPool *Pool;
259 CallBack<IOACB> callback;
260 int newfd;
261 ConnectionDetail details;
262};
263
264class CommFillCallbackData : public CommCallbackData
265{
266
267public:
268 void *operator new(size_t);
269 void operator delete(void *);
270 void deleteSelf() const;
271 CommFillCallbackData(int const anFd, CallBack<IOFCB> aCallback, comm_err_t, int);
272 virtual void callCallback();
273
274private:
275 static MemPool *Pool;
276 CallBack<IOFCB> callback;
277};
278
279class CommWriteCallbackData : public CommCallbackData
280{
281
282public:
283 void *operator new(size_t);
284 void operator delete(void *);
285 void deleteSelf() const;
286 CommWriteCallbackData(int const anFd, CallBack<IOWCB> aCallback, comm_err_t, int, int);
287 virtual void callCallback();
288
289private:
290 static MemPool *Pool;
291 CallBack<IOWCB> callback;
292 int retval;
293};
c4b7a5a9 294
62e76326 295struct _fd_debug_t
296{
43ae1d95 297 char const *close_file;
62e76326 298 int close_line;
c4b7a5a9 299};
62e76326 300
c4b7a5a9 301typedef struct _fd_debug_t fd_debug_t;
302
723123a9 303static MemPool *comm_write_pool = NULL;
58cd5bbd 304static MemPool *conn_close_pool = NULL;
c4b7a5a9 305fdc_t *fdc_table = NULL;
306fd_debug_t *fdd_table = NULL;
307dlink_list CommCallbackList;
c4b7a5a9 308
309
310/* New and improved stuff */
311
2d8c0b1a 312MemPool *CommCallbackData::Pool(NULL);
313void *
314CommCallbackData::operator new (size_t byteCount)
c4b7a5a9 315{
2d8c0b1a 316 /* derived classes with different sizes must implement their own new */
317 assert (byteCount == sizeof (CommCallbackData));
318
319 if (!Pool)
320 Pool = memPoolCreate("CommCallbackData", sizeof (CommCallbackData));
321
322 return memPoolAlloc(Pool);
c4b7a5a9 323}
324
2d8c0b1a 325void
326CommCallbackData::operator delete (void *address)
c4b7a5a9 327{
2d8c0b1a 328 memPoolFree (Pool, address);
329}
c4b7a5a9 330
2d8c0b1a 331void
332CommCallbackData::deleteSelf() const
333{
334 delete this;
335}
c4b7a5a9 336
2d8c0b1a 337MemPool *CommReadCallbackData::Pool(NULL);
338void *
339CommReadCallbackData::operator new (size_t byteCount)
340{
341 /* derived classes with different sizes must implement their own new */
342 assert (byteCount == sizeof (CommReadCallbackData));
c4b7a5a9 343
2d8c0b1a 344 if (!Pool)
345 Pool = memPoolCreate("CommReadCallbackData", sizeof (CommReadCallbackData));
c4b7a5a9 346
2d8c0b1a 347 return memPoolAlloc(Pool);
348}
c4b7a5a9 349
2d8c0b1a 350void
351CommReadCallbackData::operator delete (void *address)
352{
353 memPoolFree (Pool, address);
354}
c4b7a5a9 355
2d8c0b1a 356void
357CommReadCallbackData::deleteSelf() const
358{
359 delete this;
c4b7a5a9 360}
361
2d8c0b1a 362MemPool *CommAcceptCallbackData::Pool(NULL);
363void *
364CommAcceptCallbackData::operator new (size_t byteCount)
365{
366 /* derived classes with different sizes must implement their own new */
367 assert (byteCount == sizeof (CommAcceptCallbackData));
c4b7a5a9 368
2d8c0b1a 369 if (!Pool)
370 Pool = memPoolCreate("CommAcceptCallbackData", sizeof (CommAcceptCallbackData));
ee0989f2 371
2d8c0b1a 372 return memPoolAlloc(Pool);
373}
374
375void
376CommAcceptCallbackData::operator delete (void *address)
c4b7a5a9 377{
2d8c0b1a 378 memPoolFree (Pool, address);
379}
c4b7a5a9 380
2d8c0b1a 381void
382CommAcceptCallbackData::deleteSelf() const
383{
384 delete this;
385}
c4b7a5a9 386
2d8c0b1a 387MemPool *CommFillCallbackData::Pool(NULL);
388void *
389CommFillCallbackData::operator new (size_t byteCount)
390{
391 /* derived classes with different sizes must implement their own new */
392 assert (byteCount == sizeof (CommFillCallbackData));
c4b7a5a9 393
2d8c0b1a 394 if (!Pool)
395 Pool = memPoolCreate("CommFillCallbackData", sizeof (CommFillCallbackData));
396
397 return memPoolAlloc(Pool);
398}
399
400void
401CommFillCallbackData::operator delete (void *address)
402{
403 memPoolFree (Pool, address);
404}
405
406void
407CommFillCallbackData::deleteSelf() const
408{
409 delete this;
410}
411
412
413MemPool *CommWriteCallbackData::Pool(NULL);
414void *
415CommWriteCallbackData::operator new (size_t byteCount)
416{
417 /* derived classes with different sizes must implement their own new */
418 assert (byteCount == sizeof (CommWriteCallbackData));
419
420 if (!Pool)
421 Pool = memPoolCreate("CommWriteCallbackData", sizeof (CommWriteCallbackData));
422
423 return memPoolAlloc(Pool);
424}
425
426void
427CommWriteCallbackData::operator delete (void *address)
428{
429 memPoolFree (Pool, address);
430}
431
432void
433CommWriteCallbackData::deleteSelf() const
434{
435 delete this;
436}
437
438CommCallbackData::CommCallbackData(CommCommonCallback const &newResults) : result (newResults)
439{
440 assert(fdc_table[result.fd].active == 1);
441 registerSelf();
442}
443
444CommReadCallbackData::CommReadCallbackData(CommCommonCallback const &aResult, CallBack<IOCB> aCallback, int aRetval) : CommCallbackData(aResult), callback(aCallback), retval(aRetval)
445{}
446
447CommAcceptCallbackData::CommAcceptCallbackData(int const anFd, CallBack<IOACB> aCallback, comm_err_t anErrcode, int anErrno, int aNewFD, ConnectionDetail const &newDetails) :CommCallbackData(CommCommonCallback(anFd, anErrcode, anErrno)), callback (aCallback), newfd(aNewFD), details(newDetails)
448{}
449
450CommFillCallbackData::CommFillCallbackData(int const anFd, CallBack<IOFCB> aCallback, comm_err_t anErrcode, int anErrno) :CommCallbackData(CommCommonCallback(anFd, anErrcode, anErrno)), callback (aCallback)
451{}
c4b7a5a9 452
2d8c0b1a 453CommWriteCallbackData::CommWriteCallbackData(int const anFd, CallBack<IOWCB> aCallback, comm_err_t anErrcode, int anErrno, int aRetval) :CommCallbackData(CommCommonCallback(anFd, anErrcode, anErrno)), callback (aCallback), retval (aRetval)
454{}
455
456void
457CommCallbackData::registerSelf()
458{
62e76326 459 /* Add it to the end of the list */
2d8c0b1a 460 dlinkAddTail(this, &h_node, &CommCallbackList);
c4b7a5a9 461
62e76326 462 /* and add it to the end of the fd list */
2d8c0b1a 463 dlinkAddTail(this, &fd_node, &(fdc_table[result.fd].CommCallbackList));
464}
c4b7a5a9 465
2d8c0b1a 466void
467CommCallbackData::deRegisterSelf()
468{
469 dlinkDelete(&h_node, &CommCallbackList);
470 dlinkDelete(&fd_node, &(fdc_table[result.fd].CommCallbackList));
c4b7a5a9 471}
472
2d8c0b1a 473/*
474 * add an IO callback
475 *
476 * IO callbacks are added when we want to notify someone that some IO
477 * has finished but we don't want to risk re-entering a non-reentrant
478 * code block.
479 */
c4b7a5a9 480static void
2d8c0b1a 481comm_add_fill_callback(int fd, size_t length, comm_err_t errcode, int xerrno)
c4b7a5a9 482{
62e76326 483 CommCallbackData *cio;
c4b7a5a9 484
2d8c0b1a 485 cio = new CommFillCallbackData(fd, CallBack<IOFCB>(fdc_table[fd].fill.handler, fdc_table[fd].fill.handler_data), errcode, xerrno);
c4b7a5a9 486
62e76326 487 /* Throw our data into it */
62e76326 488 cio->sb = fdc_table[fd].fill.requestedData;
2d8c0b1a 489 cio->sb.length = length;
62e76326 490 /* Clear out fd state */
491 fdc_table[fd].fill.handler = NULL;
492 fdc_table[fd].fill.handler_data = NULL;
c4b7a5a9 493}
494
d4cb310b 495static void
496comm_add_write_callback(int fd, size_t retval, comm_err_t errcode, int xerrno)
497{
62e76326 498 CommCallbackData *cio;
d4cb310b 499
2d8c0b1a 500 cio = new CommWriteCallbackData(fd, CallBack<IOWCB>(fdc_table[fd].write.handler, fdc_table[fd].write.handler_data), errcode, xerrno, retval);
d4cb310b 501
62e76326 502 /* Clear out fd state */
503 fdc_table[fd].write.handler = NULL;
504 fdc_table[fd].write.handler_data = NULL;
d4cb310b 505}
c4b7a5a9 506
2d8c0b1a 507void
508CommReadCallbackData::callCallback()
c4b7a5a9 509{
2d8c0b1a 510 callback.handler(result.fd, buf, retval, result.errcode, result.xerrno, callback.data);
511}
62e76326 512
2d8c0b1a 513void
514CommAcceptCallbackData::callCallback()
515{
516 callback.handler(result.fd, newfd, &details, result.errcode, result.xerrno, callback.data);
517}
62e76326 518
2d8c0b1a 519void
520CommWriteCallbackData::callCallback()
521{
522 callback.handler(result.fd, buf, retval, result.errcode, result.xerrno, callback.data);
523}
62e76326 524
2d8c0b1a 525void
526CommFillCallbackData::callCallback()
527{
528 callback.handler(result.fd, sb, result.errcode, result.xerrno, callback.data);
529}
62e76326 530
2d8c0b1a 531void
532CommCallbackData::fdClosing()
533{
534 result.errcode = COMM_ERR_CLOSING;
c4b7a5a9 535}
536
2d8c0b1a 537void
538CommCallbackData::callACallback()
539{
540 assert(fdc_table[result.fd].active == 1);
541 deRegisterSelf();
542 callCallback();
543}
c4b7a5a9 544
545/*
546 * call the IO callbacks
547 *
548 * This should be called before comm_select() so code can attempt to
549 * initiate some IO.
550 *
551 * When io callbacks are added, they are added with the current
552 * sequence number. The sequence number is incremented in this routine -
553 * since callbacks are added to the _tail_ of the list, when we hit a
554 * callback with a seqnum _not_ what it was when we entered this routine,
555 * we can stop.
556 */
557void
558comm_calliocallback(void)
559{
62e76326 560 CommCallbackData *cio;
561 dlink_node *node;
562 int oldseqnum = CommCallbackSeqnum;
563
564 /* Call our callbacks until we hit NULL or the seqnum changes */
565
2d8c0b1a 566 while (CommCallbackList.head != NULL && oldseqnum != ((CommCallbackData *)CommCallbackList.head)->result.seqnum) {
567
62e76326 568 node = (dlink_node *)CommCallbackList.head;
569 cio = (CommCallbackData *)node->data;
2d8c0b1a 570 cio->callACallback();
571 cio->deleteSelf();
572 }
573}
62e76326 574
2d8c0b1a 575void
576CommRead::queueCallback(size_t retval, comm_err_t errcode, int xerrno)
577{
578 hasCallbackInvariant();
c4b7a5a9 579
2d8c0b1a 580 CommCallbackData *cio;
581 cio = new CommReadCallbackData(CommCommonCallback(fd, errcode, xerrno),callback, retval);
c4b7a5a9 582
2d8c0b1a 583 /* Throw our data into it */
584 cio->buf = buf;
585 callback = CallBack<IOCB>();
c4b7a5a9 586}
587
2d8c0b1a 588void
589CommRead::hasCallbackInvariant() const
c4b7a5a9 590{
2d8c0b1a 591 assert (hasCallback());
592}
c4b7a5a9 593
2d8c0b1a 594void
595CommRead::hasNoCallbackInvariant() const
596{
597 assert (!hasCallback());
598}
c4b7a5a9 599
2d8c0b1a 600bool
601CommRead::hasCallback() const
602{
603 return callback.handler != NULL;
c4b7a5a9 604}
605
606/*
607 * Attempt a read
608 *
609 * If the read attempt succeeds or fails, call the callback.
610 * Else, wait for another IO notification.
611 */
2d8c0b1a 612void
613CommRead::ReadTry(int fd, void *data)
c4b7a5a9 614{
62e76326 615 fdc_t *Fc = &fdc_table[fd];
2d8c0b1a 616 assert (Fc->read.fd == fd);
617 assert (data == NULL);
618 Fc->read.tryReading();
619}
c4b7a5a9 620
2d8c0b1a 621void
622CommRead::tryReading()
623{
624 hasCallbackInvariant();
c4b7a5a9 625
62e76326 626 /* Attempt a read */
627 statCounter.syscalls.sock.reads++;
628 errno = 0;
2d8c0b1a 629 int retval;
630 retval = FD_READ_METHOD(fd, buf, len);
62e76326 631 debug(5, 3) ("comm_read_try: fd %d, size %d, retval %d, errno %d\n",
2d8c0b1a 632 fd, len, retval, errno);
62e76326 633
634 if (retval < 0 && !ignoreErrno(errno)) {
635 debug(5, 3) ("comm_read_try: scheduling COMM_ERROR\n");
2d8c0b1a 636 queueCallback(0, COMM_ERROR, errno);
62e76326 637 return;
638 };
639
640 /* See if we read anything */
641 /* Note - read 0 == socket EOF, which is a valid read */
642 if (retval >= 0) {
643 fd_bytes(fd, retval, FD_READ);
2d8c0b1a 644 queueCallback(retval, COMM_OK, 0);
62e76326 645 return;
646 }
c4b7a5a9 647
62e76326 648 /* Nope, register for some more IO */
2d8c0b1a 649 commSetSelect(fd, COMM_SELECT_READ, ReadTry, NULL, 0);
c4b7a5a9 650}
651
652/*
653 * Queue a read. handler/handler_data are called when the read
654 * completes, on error, or on file descriptor close.
655 */
656void
657comm_read(int fd, char *buf, int size, IOCB *handler, void *handler_data)
658{
62e76326 659 /* Make sure we're not reading anything and we're not closing */
660 assert(fdc_table[fd].active == 1);
2d8c0b1a 661 fdc_table[fd].read.hasNoCallbackInvariant();
62e76326 662 assert(!fd_table[fd].flags.closing);
c4b7a5a9 663
62e76326 664 debug(5,4)("comm_read, queueing read for FD %d\n",fd);
528b2c61 665
62e76326 666 /* Queue a read */
2d8c0b1a 667 fdc_table[fd].read = CommRead(fd, buf, size, handler, handler_data);
668 fdc_table[fd].read.read();
669}
c4b7a5a9 670
2d8c0b1a 671void
672CommRead::read()
673{
c4b7a5a9 674#if OPTIMISTIC_IO
62e76326 675
2d8c0b1a 676 tryReading();
c4b7a5a9 677#else
2d8c0b1a 678
679 initiateActualRead();
c4b7a5a9 680#endif
681}
682
2d8c0b1a 683void
684CommRead::initiateActualRead()
685{
686 /* Register intrest in a FD read */
687 commSetSelect(fd, COMM_SELECT_READ, ReadTry, NULL, 0);
688}
689
c4b7a5a9 690static void
691comm_fill_read(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
692{
693 /* TODO use a reference to the table entry, or use C++ :] */
a46d2c0e 694 fdc_t::CommFiller *fill;
c4b7a5a9 695 assert(fdc_table[fd].active == 1);
696
697 if (flag != COMM_OK) {
698 /* Error! */
62e76326 699 /* XXX This was -1 below, but -1 can't be used for size_t parameters.
700 * The callback should set -1 to the client if needed based on the flags
701 */
702 comm_add_fill_callback(fd, 0, flag, xerrno);
703 return;
c4b7a5a9 704 }
62e76326 705
c4b7a5a9 706 /* flag is COMM_OK */
707 /* We handle EOFs as read lengths of 0! Its eww, but its consistent */
708 fill = &fdc_table[fd].fill;
62e76326 709
c4b7a5a9 710 fill->amountDone += len;
62e76326 711
2d8c0b1a 712 StoreIOBuffer *sb = &fdc_table[fd].fill.requestedData;
62e76326 713
c4b7a5a9 714 assert(fill->amountDone <= sb->length);
62e76326 715
c4b7a5a9 716 comm_add_fill_callback(fd, fill->amountDone, COMM_OK, 0);
717}
718
719/*
720 * Try filling a StoreIOBuffer with some data, and call a callback when successful
721 */
722void
723comm_fill_immediate(int fd, StoreIOBuffer sb, IOFCB *callback, void *data)
724{
725 assert(fdc_table[fd].fill.handler == NULL);
726 /* prevent confusion */
727 assert (sb.offset == 0);
728
729 /* If we don't have any data, record details and schedule a read */
730 fdc_table[fd].fill.handler = callback;
731 fdc_table[fd].fill.handler_data = data;
732 fdc_table[fd].fill.requestedData = sb;
733 fdc_table[fd].fill.amountDone = 0;
734
735 comm_read(fd, sb.data, sb.length, comm_fill_read, NULL);
736}
737
738
739/*
740 * Empty the read buffers
741 *
742 * This is a magical routine that empties the read buffers.
743 * Under some platforms (Linux) if a buffer has data in it before
744 * you call close(), the socket will hang and take quite a while
745 * to timeout.
746 */
747static void
748comm_empty_os_read_buffers(int fd)
749{
a42d5c25 750#ifdef _SQUID_LINUX_
c4b7a5a9 751 /* prevent those nasty RST packets */
752 char buf[SQUID_TCP_SO_RCVBUF];
62e76326 753
c4b7a5a9 754 if (fd_table[fd].flags.nonblocking == 1)
62e76326 755 while (FD_READ_METHOD(fd, buf, SQUID_TCP_SO_RCVBUF) > 0)
756
757 ;
c4b7a5a9 758#endif
759}
760
761
762/*
763 * Return whether a file descriptor has any pending read request callbacks
764 *
765 * Assumptions: the fd is open (ie, its not closing)
766 */
767int
768comm_has_pending_read_callback(int fd)
769{
770 dlink_node *node;
771 CommCallbackData *cd;
772
773 assert(fd_table[fd].flags.open == 1);
774 assert(fdc_table[fd].active == 1);
775
776 /*
777 * XXX I don't like having to walk the list!
778 * Instead, if this routine is called often enough, we should
779 * also maintain a linked list of _read_ events - we can just
780 * check if the list head a HEAD..
781 * - adrian
782 */
783 node = fdc_table[fd].CommCallbackList.head;
62e76326 784
c4b7a5a9 785 while (node != NULL) {
62e76326 786 cd = (CommCallbackData *)node->data;
787
2d8c0b1a 788 if (cd->getType() == COMM_CB_READ)
62e76326 789 return 1;
790
791 node = node->next;
c4b7a5a9 792 }
793
794 /* Not found */
795 return 0;
796}
797
798/*
799 * return whether a file descriptor has a read handler
800 *
801 * Assumptions: the fd is open
528b2c61 802 * the fd is a comm fd.
c4b7a5a9 803 */
528b2c61 804bool
c4b7a5a9 805comm_has_pending_read(int fd)
806{
62e76326 807 assert(fd_table[fd].flags.open == 1);
808 assert(fdc_table[fd].active == 1);
c4b7a5a9 809
2d8c0b1a 810 return (fdc_table[fd].read.hasCallback());
c4b7a5a9 811}
812
813/*
814 * Cancel a pending read. Assert that we have the right parameters,
815 * and that there are no pending read events!
816 */
817void
818comm_read_cancel(int fd, IOCB *callback, void *data)
819{
820 assert(fd_table[fd].flags.open == 1);
821 assert(fdc_table[fd].active == 1);
822
2d8c0b1a 823 assert(fdc_table[fd].read.callback == CallBack<IOCB>(callback,data));
c4b7a5a9 824
825 assert(!comm_has_pending_read_callback(fd));
826
827 /* Ok, we can be reasonably sure we won't lose any data here! */
828
829 /* Delete the callback */
2d8c0b1a 830 fdc_table[fd].read.callback = CallBack<IOCB>();
420f2ac8 831
832 /* And the IO event */
62e76326 833 commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0);
c4b7a5a9 834}
835
836
d846c273 837/*
838 * Open a filedescriptor, set some sane defaults
839 * + accept() poll time is 250ms
840 */
c4b7a5a9 841void
43ae1d95 842fdc_open(int fd, unsigned int type, char const *desc)
c4b7a5a9 843{
62e76326 844 assert(fdc_table[fd].active == 0);
c4b7a5a9 845
62e76326 846 fdc_table[fd].active = 1;
847 fdc_table[fd].fd = fd;
848 comm_accept_setcheckperiod(fd, 250);
849 fd_open(fd, type, desc);
c4b7a5a9 850}
851
852
ce767c23 853/*
854 * synchronous wrapper around udp socket functions
855 */
856
857int
7d21986b 858comm_udp_recvfrom(int fd, void *buf, size_t len, int flags,
62e76326 859
860 struct sockaddr *from, socklen_t *fromlen)
ce767c23 861{
62e76326 862 statCounter.syscalls.sock.recvfroms++;
863 return recvfrom(fd, buf, len, flags, from, fromlen);
ce767c23 864}
865
365f12a9 866int
7d21986b 867comm_udp_recv(int fd, void *buf, size_t len, int flags)
365f12a9 868{
62e76326 869 return comm_udp_recvfrom(fd, buf, len, flags, NULL, 0);
365f12a9 870}
871
f71da12c 872ssize_t
7d21986b 873comm_udp_send(int s, const void *buf, size_t len, int flags)
f71da12c 874{
62e76326 875 return send(s, buf, len, flags);
f71da12c 876}
ce767c23 877
878
d4cb310b 879/*
880 * The new-style comm_write magic
881 */
882/*
883 * Attempt a write
884 *
885 * If the write attempt succeeds or fails, call the callback.
886 * Else, wait for another IO notification.
887 */
888static void
889comm_write_try(int fd, void *data)
890{
62e76326 891 fdc_t *Fc = &fdc_table[fd];
892 int retval;
d4cb310b 893
62e76326 894 /* make sure we actually have a callback */
895 assert(Fc->write.handler != NULL);
d4cb310b 896
62e76326 897 /* Attempt a write */
898 statCounter.syscalls.sock.reads++;
899 errno = 0;
900 retval = FD_WRITE_METHOD(fd, Fc->write.buf + Fc->write.curofs, Fc->write.size - Fc->write.curofs);
901 debug(5, 3) ("comm_write_try: fd %d: tried to write %d bytes, retval %d, errno %d\n",
902 fd, Fc->write.size - Fc->write.curofs, retval, errno);
903
904 if (retval < 0 && !ignoreErrno(errno)) {
905 debug(5, 3) ("comm_write_try: can't ignore error: scheduling COMM_ERROR callback\n");
906 comm_add_write_callback(fd, 0, COMM_ERROR, errno);
907 return;
908 }
d88f85f2 909
62e76326 910 if (retval >= 0) {
911 fd_bytes(fd, retval, FD_WRITE);
912 Fc->write.curofs += retval;
913 assert(Fc->write.curofs <= Fc->write.size);
914 /* All? */
d88f85f2 915
62e76326 916 if (Fc->write.curofs == Fc->write.size) {
917 comm_add_write_callback(fd, Fc->write.size, COMM_OK, 0);
918 return;
919 }
920 }
d4cb310b 921
62e76326 922 /* if we get here, we need to write more! */
923 commSetSelect(fd, COMM_SELECT_WRITE, comm_write_try, NULL, 0);
d4cb310b 924}
925
cf3c0ee3 926/*
927 * Queue a write. handler/handler_data are called when the write fully
928 * completes, on error, or on file descriptor close.
929 */
930void
dba1a67d 931comm_write(int fd, const char *buf, size_t size, IOWCB *handler, void *handler_data)
cf3c0ee3 932{
62e76326 933 /* Make sure we're not writing anything and we're not closing */
934 assert(fdc_table[fd].active == 1);
935 assert(fdc_table[fd].write.handler == NULL);
936 assert(!fd_table[fd].flags.closing);
cf3c0ee3 937
62e76326 938 /* Queue a read */
939 fdc_table[fd].write.buf = buf;
940 fdc_table[fd].write.size = size;
941 fdc_table[fd].write.handler = handler;
942 fdc_table[fd].write.handler_data = handler_data;
943 fdc_table[fd].write.curofs = 0;
cf3c0ee3 944
945#if OPTIMISTIC_IO
62e76326 946
947 comm_write_try(fd, NULL);
cf3c0ee3 948#else
62e76326 949 /* Register intrest in a FD read */
950 commSetSelect(fd, COMM_SELECT_WRITE, comm_write_try, NULL, 0);
cf3c0ee3 951#endif
952}
d4cb310b 953
3c1a197f 954/*
955 * New-style accept stuff
956 */
957
958/*
959 * Set the check delay on accept()ing when we're out of FDs
960 *
961 * The premise behind this is that we can hit a situation where
962 * we've hit our reserved filedescriptor limit and we don't want
963 * to accept any more connections until some others have closed.
964 *
965 * This code will set the period which we register an event to check
966 * to see whether we _have_ enough open FDs to re-register for IO.
967 */
968void
969comm_accept_setcheckperiod(int fd, int mdelay)
970{
62e76326 971 assert(fdc_table[fd].active == 1);
972 assert(mdelay != 0);
973 fdc_table[fd].accept.accept.check_delay = mdelay;
3c1a197f 974}
975
976/*
977 * Our periodic accept() suitability checker..
978 */
979static void
980comm_accept_check_event(void *data)
981{
62e76326 982 static time_t last_warn = 0;
983 int fd = ((fdc_t *)(data))->fd;
3c1a197f 984
62e76326 985 if (fdNFree() < RESERVED_FD) {
986 commSetSelect(fd, COMM_SELECT_READ, comm_accept_try, NULL, 0);
987 return;
988 }
989
990 if (last_warn + 15 < squid_curtime) {
991 debug(33, 0) ("WARNING! Your cache is running out of filedescriptors\n");
992 last_warn = squid_curtime;
993 }
994
995 eventAdd("comm_accept_check_event", comm_accept_check_event, &fdc_table[fd],
996 1000.0 / (double)(fdc_table[fd].accept.accept.check_delay), 1);
3c1a197f 997}
998
999
d4cb310b 1000
c4b7a5a9 1001/* Older stuff */
309ad3b6 1002
b8d8561b 1003static void
3d7e9d7c 1004CommWriteStateCallbackAndFree(int fd, comm_err_t code)
9864ee44 1005{
f17936ab 1006 CommWriteStateData *CommWriteState = fd_table[fd].rwstate;
1007 CWCB *callback = NULL;
fa80a8ef 1008 void *cbdata;
a56a3abe 1009 fd_table[fd].rwstate = NULL;
62e76326 1010
f17936ab 1011 if (CommWriteState == NULL)
62e76326 1012 return;
1013
c0dec081 1014 if (CommWriteState->free_func) {
62e76326 1015 FREE *free_func = CommWriteState->free_func;
1016 void *free_buf = CommWriteState->buf;
1017 CommWriteState->free_func = NULL;
1018 CommWriteState->buf = NULL;
1019 free_func(free_buf);
9864ee44 1020 }
62e76326 1021
f17936ab 1022 callback = CommWriteState->handler;
1023 CommWriteState->handler = NULL;
62e76326 1024
fa80a8ef 1025 if (callback && cbdataReferenceValidDone(CommWriteState->handler_data, &cbdata))
62e76326 1026 callback(fd, CommWriteState->buf, CommWriteState->offset, code, cbdata);
1027
723123a9 1028 memPoolFree(comm_write_pool, CommWriteState);
9864ee44 1029}
1030
090089c4 1031/* Return the local port associated with fd. */
b8d8561b 1032u_short
1033comm_local_port(int fd)
090089c4 1034{
62e76326 1035
090089c4 1036 struct sockaddr_in addr;
6637e3a5 1037 socklen_t addr_len = 0;
76f87348 1038 fde *F = &fd_table[fd];
090089c4 1039
090089c4 1040 /* If the fd is closed already, just return */
62e76326 1041
60c0b5a2 1042 if (!F->flags.open) {
62e76326 1043 debug(5, 0) ("comm_local_port: FD %d has been closed.\n", fd);
1044 return 0;
090089c4 1045 }
62e76326 1046
76f87348 1047 if (F->local_port)
62e76326 1048 return F->local_port;
1049
090089c4 1050 addr_len = sizeof(addr);
62e76326 1051
090089c4 1052 if (getsockname(fd, (struct sockaddr *) &addr, &addr_len)) {
62e76326 1053 debug(50, 1) ("comm_local_port: Failed to retrieve TCP/UDP port number for socket: FD %d: %s\n", fd, xstrerror());
1054 return 0;
090089c4 1055 }
62e76326 1056
76f87348 1057 F->local_port = ntohs(addr.sin_port);
5f6ac48b 1058 debug(5, 6) ("comm_local_port: FD %d: port %d\n", fd, (int) F->local_port);
76f87348 1059 return F->local_port;
090089c4 1060}
1061
3d7e9d7c 1062static comm_err_t
62e76326 1063
b8d8561b 1064commBind(int s, struct in_addr in_addr, u_short port)
090089c4 1065{
62e76326 1066
090089c4 1067 struct sockaddr_in S;
090089c4 1068
090089c4 1069 memset(&S, '\0', sizeof(S));
1070 S.sin_family = AF_INET;
1071 S.sin_port = htons(port);
30a4f2a8 1072 S.sin_addr = in_addr;
83704487 1073 statCounter.syscalls.sock.binds++;
62e76326 1074
090089c4 1075 if (bind(s, (struct sockaddr *) &S, sizeof(S)) == 0)
62e76326 1076 return COMM_OK;
1077
a3d5953d 1078 debug(50, 0) ("commBind: Cannot bind socket FD %d to %s:%d: %s\n",
62e76326 1079 s,
1080 S.sin_addr.s_addr == INADDR_ANY ? "*" : inet_ntoa(S.sin_addr),
1081 (int) port,
1082 xstrerror());
1083
090089c4 1084 return COMM_ERROR;
1085}
1086
1087/* Create a socket. Default is blocking, stream (TCP) socket. IO_TYPE
d6827718 1088 * is OR of flags specified in comm.h. Defaults TOS */
b8d8561b 1089int
16b204c4 1090comm_open(int sock_type,
62e76326 1091 int proto,
1092
1093 struct in_addr addr,
1094 u_short port,
1095 int flags,
1096 const char *note)
d6827718 1097{
1098 return comm_openex(sock_type, proto, addr, port, flags, 0, note);
1099}
1100
2d8c0b1a 1101static bool
1102limitError(int const anErrno)
1103{
1104 return anErrno == ENFILE || anErrno == EMFILE;
1105}
d6827718 1106
1107/* Create a socket. Default is blocking, stream (TCP) socket. IO_TYPE
1108 * is OR of flags specified in defines.h:COMM_* */
1109int
1110comm_openex(int sock_type,
62e76326 1111 int proto,
1112
1113 struct in_addr addr,
1114 u_short port,
1115 int flags,
1116 unsigned char TOS,
1117 const char *note)
090089c4 1118{
1119 int new_socket;
9056f553 1120 int tos = 0;
76f87348 1121 fde *F = NULL;
090089c4 1122
88bfe092 1123 PROF_start(comm_open);
090089c4 1124 /* Create socket for accepting new connections. */
83704487 1125 statCounter.syscalls.sock.sockets++;
62e76326 1126
1127 if ((new_socket = socket(AF_INET, sock_type, proto)) < 0)
1128 {
1129 /* Increase the number of reserved fd's if calls to socket()
1130 * are failing because the open file table is full. This
1131 * limits the number of simultaneous clients */
1132
2d8c0b1a 1133 if (limitError(errno)) {
62e76326 1134 debug(50, 1) ("comm_open: socket failure: %s\n", xstrerror());
1135 fdAdjustReserved();
2d8c0b1a 1136 } else {
62e76326 1137 debug(50, 0) ("comm_open: socket failure: %s\n", xstrerror());
1138 }
1139
1140 PROF_stop(comm_open);
1141 return -1;
090089c4 1142 }
62e76326 1143
d6827718 1144 /* set TOS if needed */
62e76326 1145 if (TOS)
1146 {
d6827718 1147#ifdef IP_TOS
62e76326 1148 tos = TOS;
1149
1150 if (setsockopt(new_socket, IPPROTO_IP, IP_TOS, (char *) &tos, sizeof(int)) < 0)
1151 debug(50, 1) ("comm_open: setsockopt(IP_TOS) on FD %d: %s\n",
1152 new_socket, xstrerror());
1153
d6827718 1154#else
62e76326 1155
1156 debug(50, 0) ("comm_open: setsockopt(IP_TOS) not supported on this platform\n");
1157
d6827718 1158#endif
62e76326 1159
d6827718 1160 }
62e76326 1161
090089c4 1162 /* update fdstat */
365e5b34 1163 debug(5, 5) ("comm_open: FD %d is a new socket\n", new_socket);
62e76326 1164
5c5783a2 1165 fd_open(new_socket, FD_SOCKET, note);
62e76326 1166
c4b7a5a9 1167 fdd_table[new_socket].close_file = NULL;
62e76326 1168
c4b7a5a9 1169 fdd_table[new_socket].close_line = 0;
62e76326 1170
c4b7a5a9 1171 assert(fdc_table[new_socket].active == 0);
62e76326 1172
c4b7a5a9 1173 fdc_table[new_socket].active = 1;
62e76326 1174
76f87348 1175 F = &fd_table[new_socket];
62e76326 1176
d6827718 1177 F->local_addr = addr;
62e76326 1178
d6827718 1179 F->tos = tos;
62e76326 1180
79a15e0a 1181 if (!(flags & COMM_NOCLOEXEC))
62e76326 1182 commSetCloseOnExec(new_socket);
1183
cdc33f35 1184 if ((flags & COMM_REUSEADDR))
62e76326 1185 commSetReuseAddr(new_socket);
1186
1187 if (port > (u_short) 0)
1188 {
1189 commSetNoLinger(new_socket);
1190
1191 if (opt_reuseaddr)
1192 commSetReuseAddr(new_socket);
090089c4 1193 }
62e76326 1194
1195 if (addr.s_addr != no_addr.s_addr)
1196 {
1197 if (commBind(new_socket, addr, port) != COMM_OK) {
1198 comm_close(new_socket);
1199 return -1;
1200 PROF_stop(comm_open);
1201 }
23ff6968 1202 }
62e76326 1203
76f87348 1204 F->local_port = port;
090089c4 1205
79a15e0a 1206 if (flags & COMM_NONBLOCKING)
62e76326 1207 if (commSetNonBlocking(new_socket) == COMM_ERROR)
1208 {
1209 return -1;
1210 PROF_stop(comm_open);
1211 }
1212
30a4f2a8 1213#ifdef TCP_NODELAY
1214 if (sock_type == SOCK_STREAM)
62e76326 1215 commSetTcpNoDelay(new_socket);
1216
30a4f2a8 1217#endif
62e76326 1218
1241e63e 1219 if (Config.tcpRcvBufsz > 0 && sock_type == SOCK_STREAM)
62e76326 1220 commSetTcpRcvbuf(new_socket, Config.tcpRcvBufsz);
1221
88bfe092 1222 PROF_stop(comm_open);
62e76326 1223
090089c4 1224 return new_socket;
1225}
1226
e5f6c5c2 1227void
4f92c80c 1228commConnectStart(int fd, const char *host, u_short port, CNCB * callback, void *data)
e924600d 1229{
28c60158 1230 ConnectStateData *cs;
5117e471 1231 debug(5, 3) ("commConnectStart: FD %d, data %p, %s:%d\n", fd, data, host, (int) port);
72711e31 1232 cs = cbdataAlloc(ConnectStateData);
03a1ee42 1233 cs->fd = fd;
e924600d 1234 cs->host = xstrdup(host);
1235 cs->port = port;
2d8c0b1a 1236 cs->callback = CallBack<CNCB>(callback,cbdataReference(data));
e924600d 1237 comm_add_close_handler(fd, commConnectFree, cs);
f88211e8 1238 cs->locks++;
8407afee 1239 ipcache_nbgethostbyname(host, commConnectDnsHandle, cs);
edeb28fd 1240}
1241
1242static void
03a1ee42 1243commConnectDnsHandle(const ipcache_addrs * ia, void *data)
edeb28fd 1244{
e6ccf245 1245 ConnectStateData *cs = (ConnectStateData *)data;
f88211e8 1246 assert(cs->locks == 1);
1247 cs->locks--;
62e76326 1248
edeb28fd 1249 if (ia == NULL) {
62e76326 1250 debug(5, 3) ("commConnectDnsHandle: Unknown host: %s\n", cs->host);
1251
1252 if (!dns_error_message) {
1253 dns_error_message = "Unknown DNS error";
1254 debug(5, 1) ("commConnectDnsHandle: Bad dns_error_message\n");
1255 }
1256
1257 assert(dns_error_message != NULL);
2d8c0b1a 1258 cs->callCallback(COMM_ERR_DNS, 0);
62e76326 1259 return;
edeb28fd 1260 }
62e76326 1261
f076b37b 1262 assert(ia->cur < ia->count);
edeb28fd 1263 cs->in_addr = ia->in_addrs[ia->cur];
52926044 1264 ipcacheCycleAddr(cs->host, NULL);
22c653cd 1265 cs->addrcount = ia->count;
1266 cs->connstart = squid_curtime;
2d8c0b1a 1267 cs->connect();
e924600d 1268}
1269
2d8c0b1a 1270void
1271ConnectStateData::callCallback(comm_err_t status, int xerrno)
1272{
1273 debug(5, 3) ("commConnectCallback: fd %d, data %p\n", fd, callback.data);
1274 comm_remove_close_handler(fd, commConnectFree, this);
1275 CallBack<CNCB> aCallback = callback;
1276 callback = CallBack<CNCB>();
e1b16349 1277 commSetTimeout(fd, -1, NULL, NULL);
62e76326 1278
2d8c0b1a 1279 if (cbdataReferenceValid(aCallback.data))
1280 aCallback.handler(fd, status, xerrno, aCallback.data);
62e76326 1281
2d8c0b1a 1282 cbdataReferenceDone(aCallback.data);
744c68f5 1283
1284 commConnectFree(fd, this);
f88211e8 1285}
1286
e924600d 1287static void
9daca08e 1288commConnectFree(int fd, void *data)
e924600d 1289{
e6ccf245 1290 ConnectStateData *cs = (ConnectStateData *)data;
9daca08e 1291 debug(5, 3) ("commConnectFree: FD %d\n", fd);
2d8c0b1a 1292 cbdataReferenceDone(cs->callback.data);
8407afee 1293 safe_free(cs->host);
1294 cbdataFree(cs);
e924600d 1295}
1296
2d8c0b1a 1297static void
1298copyFDFlags(int to, fde *F)
1299{
1300 if (F->flags.close_on_exec)
1301 commSetCloseOnExec(to);
1302
1303 if (F->flags.nonblocking)
1304 commSetNonBlocking(to);
1305
1306#ifdef TCP_NODELAY
1307
1308 if (F->flags.nodelay)
1309 commSetTcpNoDelay(to);
1310
1311#endif
1312
1313 if (Config.tcpRcvBufsz > 0)
1314 commSetTcpRcvbuf(to, Config.tcpRcvBufsz);
1315}
1316
22c653cd 1317/* Reset FD so that we can connect() again */
edeb28fd 1318static int
22c653cd 1319commResetFD(ConnectStateData * cs)
edeb28fd 1320{
2d8c0b1a 1321 if (!cbdataReferenceValid(cs->callback.data))
62e76326 1322 return 0;
1323
83704487 1324 statCounter.syscalls.sock.sockets++;
62e76326 1325
2d8c0b1a 1326 int fd2 = socket(AF_INET, SOCK_STREAM, 0);
62e76326 1327
83704487 1328 statCounter.syscalls.sock.sockets++;
62e76326 1329
edeb28fd 1330 if (fd2 < 0) {
62e76326 1331 debug(5, 0) ("commResetFD: socket: %s\n", xstrerror());
1332
1333 if (ENFILE == errno || EMFILE == errno)
1334 fdAdjustReserved();
1335
1336 return 0;
edeb28fd 1337 }
62e76326 1338
22c653cd 1339 if (dup2(fd2, cs->fd) < 0) {
62e76326 1340 debug(5, 0) ("commResetFD: dup2: %s\n", xstrerror());
1341
1342 if (ENFILE == errno || EMFILE == errno)
1343 fdAdjustReserved();
1344
1345 close(fd2);
1346
1347 return 0;
edeb28fd 1348 }
62e76326 1349
edeb28fd 1350 close(fd2);
2d8c0b1a 1351 fde *F = &fd_table[cs->fd];
b5568a61 1352 fd_table[cs->fd].flags.called_connect = 0;
09544acc 1353 /*
1354 * yuck, this has assumptions about comm_open() arguments for
1355 * the original socket
1356 */
62e76326 1357
d6827718 1358 if (commBind(cs->fd, F->local_addr, F->local_port) != COMM_OK) {
62e76326 1359 debug(5, 0) ("commResetFD: bind: %s\n", xstrerror());
1360 return 0;
09544acc 1361 }
62e76326 1362
d6827718 1363#ifdef IP_TOS
1364 if (F->tos) {
2d8c0b1a 1365 if (setsockopt(cs->fd, IPPROTO_IP, IP_TOS, (char *) &F->tos, sizeof(int)) < 0)
62e76326 1366 debug(50, 1) ("commResetFD: setsockopt(IP_TOS) on FD %d: %s\n", cs->fd, xstrerror());
d6827718 1367 }
62e76326 1368
d6827718 1369#endif
2d8c0b1a 1370 copyFDFlags (cs->fd, F);
62e76326 1371
edeb28fd 1372 return 1;
1373}
1374
22c653cd 1375static int
1376commRetryConnect(ConnectStateData * cs)
1377{
1378 assert(cs->addrcount > 0);
62e76326 1379
22c653cd 1380 if (cs->addrcount == 1) {
62e76326 1381 if (cs->tries >= Config.retry.maxtries)
1382 return 0;
1383
1384 if (squid_curtime - cs->connstart > Config.Timeout.connect)
1385 return 0;
22c653cd 1386 } else {
62e76326 1387 if (cs->tries > cs->addrcount)
1388 return 0;
22c653cd 1389 }
62e76326 1390
22c653cd 1391 return commResetFD(cs);
1392}
1393
e924600d 1394/* Connect SOCK to specified DEST_PORT at DEST_HOST. */
2d8c0b1a 1395void
1396ConnectStateData::Connect (int fd, void *me)
090089c4 1397{
2d8c0b1a 1398 ConnectStateData *cs = (ConnectStateData *)me;
1399 assert (cs->fd == fd);
1400 cs->connect();
1401}
1402
1403void
1404ConnectStateData::defaults()
1405{
1406 S.sin_family = AF_INET;
1407 S.sin_addr = in_addr;
1408 S.sin_port = htons(port);
62e76326 1409
2d8c0b1a 1410 if (Config.onoff.log_fqdn)
1411 fqdncache_gethostbyaddr(S.sin_addr, FQDN_LOOKUP_IF_MISS);
1412}
62e76326 1413
2d8c0b1a 1414void
1415ConnectStateData::connect()
1416{
1417 if (S.sin_addr.s_addr == 0)
1418 defaults();
62e76326 1419
2d8c0b1a 1420 switch (comm_connect_addr(fd, &S)) {
62e76326 1421
e5f6c5c2 1422 case COMM_INPROGRESS:
62e76326 1423 debug(5, 5) ("commConnectHandle: FD %d: COMM_INPROGRESS\n", fd);
2d8c0b1a 1424 commSetSelect(fd, COMM_SELECT_WRITE, ConnectStateData::Connect, this, 0);
62e76326 1425 break;
1426
e5f6c5c2 1427 case COMM_OK:
2d8c0b1a 1428 ipcacheMarkGoodAddr(host, S.sin_addr);
1429 callCallback(COMM_OK, 0);
62e76326 1430 break;
1431
e5f6c5c2 1432 default:
2d8c0b1a 1433 tries++;
1434 ipcacheMarkBadAddr(host, S.sin_addr);
62e76326 1435
1436 if (Config.onoff.test_reachability)
2d8c0b1a 1437 netdbDeleteAddrNetwork(S.sin_addr);
62e76326 1438
2d8c0b1a 1439 if (commRetryConnect(this)) {
1440 locks++;
1441 ipcache_nbgethostbyname(host, commConnectDnsHandle, this);
62e76326 1442 } else {
2d8c0b1a 1443 callCallback(COMM_ERR_CONNECT, errno);
62e76326 1444 }
090089c4 1445 }
090089c4 1446}
22c653cd 1447
b8d8561b 1448int
4f92c80c 1449commSetTimeout(int fd, int timeout, PF * handler, void *data)
090089c4 1450{
a3d5953d 1451 debug(5, 3) ("commSetTimeout: FD %d timeout %d\n", fd, timeout);
03eb2f01 1452 assert(fd >= 0);
1453 assert(fd < Squid_MaxFD);
2d8c0b1a 1454 fde *F = &fd_table[fd];
60c0b5a2 1455 assert(F->flags.open);
62e76326 1456
5c5783a2 1457 if (timeout < 0) {
62e76326 1458 cbdataReferenceDone(F->timeout_data);
1459 F->timeout_handler = NULL;
1460 F->timeout = 0;
5849612f 1461 } else {
62e76326 1462 assert(handler || F->timeout_handler);
1463
1464 if (handler) {
1465 cbdataReferenceDone(F->timeout_data);
1466 F->timeout_handler = handler;
1467 F->timeout_data = cbdataReference(data);
1468 }
1469
1470 F->timeout = squid_curtime + (time_t) timeout;
30a4f2a8 1471 }
62e76326 1472
a3fa14bf 1473 return F->timeout;
090089c4 1474}
1475
b8d8561b 1476int
62e76326 1477
0ee4272b 1478comm_connect_addr(int sock, const struct sockaddr_in *address)
090089c4 1479{
3d7e9d7c 1480 comm_err_t status = COMM_OK;
76f87348 1481 fde *F = &fd_table[sock];
090089c4 1482 int x;
b5568a61 1483 int err = 0;
9689d97c 1484 socklen_t errlen;
489b22c1 1485 assert(ntohs(address->sin_port) != 0);
88bfe092 1486 PROF_start(comm_connect_addr);
090089c4 1487 /* Establish connection. */
b5568a61 1488 errno = 0;
62e76326 1489
1490 if (!F->flags.called_connect)
1491 {
1492 F->flags.called_connect = 1;
1493 statCounter.syscalls.sock.connects++;
1494
1495 x = connect(sock, (struct sockaddr *) address, sizeof(*address));
1496
1497 if (x < 0)
1498 debug(5, 9) ("connect FD %d: %s\n", sock, xstrerror());
1499 } else
1500 {
140e2c0b 1501#if defined(_SQUID_NEWSOS6_)
62e76326 1502 /* Makoto MATSUSHITA <matusita@ics.es.osaka-u.ac.jp> */
1503
1504 connect(sock, (struct sockaddr *) address, sizeof(*address));
1505
1506 if (errno == EINVAL) {
1507 errlen = sizeof(err);
1508 x = getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &errlen);
1509
1510 if (x >= 0)
1511 errno = x;
1512 }
1513
33ac9442 1514#else
62e76326 1515 errlen = sizeof(err);
1516
1517 x = getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &errlen);
1518
1519 if (x == 0)
1520 errno = err;
1521
b5568a61 1522#if defined(_SQUID_SOLARIS_)
62e76326 1523 /*
1524 * Solaris 2.4's socket emulation doesn't allow you
1525 * to determine the error from a failed non-blocking
1526 * connect and just returns EPIPE. Create a fake
1527 * error message for connect. -- fenner@parc.xerox.com
1528 */
1529 if (x < 0 && errno == EPIPE)
1530 errno = ENOTCONN;
1531
33ac9442 1532#endif
30a4f2a8 1533#endif
62e76326 1534
e5f6c5c2 1535 }
62e76326 1536
88bfe092 1537 PROF_stop(comm_connect_addr);
62e76326 1538
b5568a61 1539 if (errno == 0 || errno == EISCONN)
62e76326 1540 status = COMM_OK;
b5568a61 1541 else if (ignoreErrno(errno))
62e76326 1542 status = COMM_INPROGRESS;
b5568a61 1543 else
62e76326 1544 return COMM_ERROR;
1545
76f87348 1546 xstrncpy(F->ipaddr, inet_ntoa(address->sin_addr), 16);
62e76326 1547
76f87348 1548 F->remote_port = ntohs(address->sin_port);
62e76326 1549
1550 if (status == COMM_OK)
1551 {
1552 debug(5, 10) ("comm_connect_addr: FD %d connected to %s:%d\n",
1553 sock, F->ipaddr, F->remote_port);
1554 } else if (status == COMM_INPROGRESS)
1555 {
1556 debug(5, 10) ("comm_connect_addr: FD %d connection pending\n", sock);
090089c4 1557 }
62e76326 1558
090089c4 1559 return status;
1560}
1561
1562/* Wait for an incoming connection on FD. FD should be a socket returned
1563 * from comm_listen. */
ee0989f2 1564static int
1565comm_old_accept(int fd, ConnectionDetail &details)
090089c4 1566{
88bfe092 1567 PROF_start(comm_accept);
ee0989f2 1568 statCounter.syscalls.sock.accepts++;
1569 int sock;
1570 socklen_t Slen = sizeof(details.peer);
62e76326 1571
ee0989f2 1572 if ((sock = accept(fd, (struct sockaddr *) &details.peer, &Slen)) < 0) {
62e76326 1573 PROF_stop(comm_accept);
1574
1575 if (ignoreErrno(errno))
1576 {
1577 debug(50, 5) ("comm_old_accept: FD %d: %s\n", fd, xstrerror());
1578 return COMM_NOMESSAGE;
1579 } else if (ENFILE == errno || EMFILE == errno)
1580 {
1581 debug(50, 3) ("comm_old_accept: FD %d: %s\n", fd, xstrerror());
1582 return COMM_ERROR;
1583 } else
1584 {
1585 debug(50, 1) ("comm_old_accept: FD %d: %s\n", fd, xstrerror());
1586 return COMM_ERROR;
1587 }
090089c4 1588 }
62e76326 1589
ee0989f2 1590 Slen = sizeof(details.me);
1591 memset(&details.me, '\0', Slen);
62e76326 1592
ee0989f2 1593 getsockname(sock, (struct sockaddr *) &details.me, &Slen);
3ca60c86 1594 commSetCloseOnExec(sock);
090089c4 1595 /* fdstat update */
5c5783a2 1596 fd_open(sock, FD_SOCKET, "HTTP Request");
c4b7a5a9 1597 fdd_table[sock].close_file = NULL;
1598 fdd_table[sock].close_line = 0;
1599 fdc_table[sock].active = 1;
ee0989f2 1600 fde *F = &fd_table[sock];
1601 xstrncpy(F->ipaddr, inet_ntoa(details.peer.sin_addr), 16);
1602 F->remote_port = htons(details.peer.sin_port);
1603 F->local_port = htons(details.me.sin_port);
090089c4 1604 commSetNonBlocking(sock);
88bfe092 1605 PROF_stop(comm_accept);
090089c4 1606 return sock;
1607}
1608
cb201b7e 1609void
1610commCallCloseHandlers(int fd)
1611{
76f87348 1612 fde *F = &fd_table[fd];
a3d5953d 1613 debug(5, 5) ("commCallCloseHandlers: FD %d\n", fd);
62e76326 1614
8000a965 1615 while (F->closeHandler != NULL) {
62e76326 1616 close_handler ch = *F->closeHandler;
1617 memPoolFree(conn_close_pool, F->closeHandler); /* AAA */
1618 F->closeHandler = ch.next;
1619 ch.next = NULL;
1620 debug(5, 5) ("commCallCloseHandlers: ch->handler=%p data=%p\n", ch.handler, ch.data);
1621
1622 if (cbdataReferenceValid(ch.data))
1623 ch.handler(fd, ch.data);
1624
1625 cbdataReferenceDone(ch.data);
cb201b7e 1626 }
1627}
1628
5492ad1d 1629#if LINGERING_CLOSE
1630static void
1631commLingerClose(int fd, void *unused)
1632{
1633 LOCAL_ARRAY(char, buf, 1024);
1634 int n;
1f7c9178 1635 n = FD_READ_METHOD(fd, buf, 1024);
62e76326 1636
5492ad1d 1637 if (n < 0)
62e76326 1638 debug(5, 3) ("commLingerClose: FD %d read: %s\n", fd, xstrerror());
1639
5492ad1d 1640 comm_close(fd);
1641}
1642
1643static void
1644commLingerTimeout(int fd, void *unused)
1645{
1646 debug(5, 3) ("commLingerTimeout: FD %d\n", fd);
1647 comm_close(fd);
1648}
1649
1650/*
1651 * Inspired by apache
1652 */
1653void
1654comm_lingering_close(int fd)
1655{
d4c19b39 1656#if USE_SSL
62e76326 1657
d4c19b39 1658 if (fd_table[fd].ssl)
62e76326 1659 ssl_shutdown_method(fd);
1660
d4c19b39 1661#endif
62e76326 1662
5492ad1d 1663 if (shutdown(fd, 1) < 0) {
62e76326 1664 comm_close(fd);
1665 return;
5492ad1d 1666 }
62e76326 1667
5492ad1d 1668 fd_note(fd, "lingering close");
1669 commSetTimeout(fd, 10, commLingerTimeout, NULL);
1670 commSetSelect(fd, COMM_SELECT_READ, commLingerClose, NULL, 0);
1671}
62e76326 1672
5492ad1d 1673#endif
1674
98264874 1675/*
1676 * enable linger with time of 0 so that when the socket is
1677 * closed, TCP generates a RESET
1678 */
1679void
1680comm_reset_close(int fd)
1681{
62e76326 1682
98264874 1683 struct linger L;
1684 L.l_onoff = 1;
1685 L.l_linger = 0;
62e76326 1686
98264874 1687 if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &L, sizeof(L)) < 0)
62e76326 1688 debug(50, 0) ("commResetTCPClose: FD %d: %s\n", fd, xstrerror());
1689
98264874 1690 comm_close(fd);
1691}
1692
2d8c0b1a 1693void
1694CommRead::nullCallback()
1695{
1696 callback = CallBack<IOCB>();
1697}
1698
1699void
1700AcceptFD::nullCallback()
1701{
1702 callback = CallBack<IOACB>();
1703}
1704
1705void
1706CommRead::doCallback(comm_err_t errcode, int xerrno)
1707{
1708 if (callback.handler)
1709 callback.handler(fd, buf, 0, errcode, xerrno, callback.data);
1710
1711 nullCallback();
1712}
1713
1714void
1715AcceptFD::doCallback(int fd, int newfd, comm_err_t errcode, int xerrno, ConnectionDetail *connDetails)
1716{
1717 if (callback.handler) {
1718 CallBack<IOACB> aCallback = callback;
1719 nullCallback();
1720 aCallback.handler(fd, newfd, connDetails, errcode, xerrno, aCallback.data);
1721 }
1722}
c4b7a5a9 1723
1724/*
1725 * Close the socket fd.
1726 *
1727 * + call write handlers with ERR_CLOSING
1728 * + call read handlers with ERR_CLOSING
1729 * + call closing handlers
a46d2c0e 1730 *
1731 * NOTE: COMM_ERR_CLOSING will NOT be called for CommReads' sitting in a
1732 * DeferredReadManager.
c4b7a5a9 1733 */
b8d8561b 1734void
43ae1d95 1735_comm_close(int fd, char const *file, int line)
090089c4 1736{
76f87348 1737 fde *F = NULL;
c4b7a5a9 1738 dlink_node *node;
1739 CommCallbackData *cio;
1f7c9178 1740
a3d5953d 1741 debug(5, 5) ("comm_close: FD %d\n", fd);
03eb2f01 1742 assert(fd >= 0);
1743 assert(fd < Squid_MaxFD);
76f87348 1744 F = &fd_table[fd];
c4b7a5a9 1745 fdd_table[fd].close_file = file;
1746 fdd_table[fd].close_line = line;
1f7c9178 1747
58a6c186 1748 if (F->flags.closing)
62e76326 1749 return;
1750
60c0b5a2 1751 if (shutting_down && (!F->flags.open || F->type == FD_FILE))
62e76326 1752 return;
1753
60c0b5a2 1754 assert(F->flags.open);
62e76326 1755
c4b7a5a9 1756 /* The following fails because ipc.c is doing calls to pipe() to create sockets! */
62e76326 1757 assert(fdc_table[fd].active == 1);
1758
76f87348 1759 assert(F->type != FD_FILE);
62e76326 1760
88bfe092 1761 PROF_start(comm_close);
62e76326 1762
58a6c186 1763 F->flags.closing = 1;
62e76326 1764
d4c19b39 1765#if USE_SSL
62e76326 1766
d4c19b39 1767 if (F->ssl)
62e76326 1768 ssl_shutdown_method(fd);
1769
d4c19b39 1770#endif
62e76326 1771
fa80a8ef 1772 commSetTimeout(fd, -1, NULL, NULL);
62e76326 1773
96f1be5d 1774 CommWriteStateCallbackAndFree(fd, COMM_ERR_CLOSING);
c4b7a5a9 1775
3c1a197f 1776 /* Delete any accept check */
1777 if (eventFind(comm_accept_check_event, &fdc_table[fd])) {
1778 eventDelete(comm_accept_check_event, &fdc_table[fd]);
1779 }
1780
691476e2 1781 /* Do callbacks for read/accept/fill routines, if any */
2d8c0b1a 1782 assert (fd == fdc_table[fd].read.fd);
62e76326 1783
2d8c0b1a 1784 fdc_table[fd].read.doCallback(COMM_ERR_CLOSING, 0);
1785
1786 fdc_table[fd].accept.accept.doCallback(fd, -1, COMM_ERR_CLOSING, 0, NULL);
62e76326 1787
511e2383 1788 if (fdc_table[fd].fill.handler) {
691476e2 1789 fdc_table[fd].fill.handler(fd, fdc_table[fd].fill.requestedData, COMM_ERR_CLOSING, 0,
62e76326 1790 fdc_table[fd].fill.handler_data);
1791 fdc_table[fd].fill.handler = NULL;
511e2383 1792 }
62e76326 1793
511e2383 1794 /* Complete (w/ COMM_ERR_CLOSING!) any pending io callbacks */
c4b7a5a9 1795 while (fdc_table[fd].CommCallbackList.head != NULL) {
62e76326 1796 node = fdc_table[fd].CommCallbackList.head;
1797 cio = (CommCallbackData *)node->data;
2d8c0b1a 1798 assert(fd == cio->result.fd); /* just paranoid */
62e76326 1799 /* We're closing! */
2d8c0b1a 1800 cio->fdClosing();
1801 cio->callACallback();
1802 cio->deleteSelf();
c4b7a5a9 1803 }
1804
cb201b7e 1805 commCallCloseHandlers(fd);
62e76326 1806
b716a8ad 1807 if (F->uses) /* assume persistent connect count */
62e76326 1808 pconnHistCount(1, F->uses);
1809
a7ad6e4e 1810 comm_empty_os_read_buffers(fd);
62e76326 1811
d4c19b39 1812#if USE_SSL
62e76326 1813
d4c19b39 1814 if (F->ssl) {
62e76326 1815 SSL_free(F->ssl);
1816 F->ssl = NULL;
d4c19b39 1817 }
62e76326 1818
d4c19b39 1819#endif
5c5783a2 1820 fd_close(fd); /* update fdstat */
62e76326 1821
5874bf28 1822 close(fd);
62e76326 1823
c4b7a5a9 1824 fdc_table[fd].active = 0;
62e76326 1825
a46d2c0e 1826 if (fdc_table[fd].half_closed) {
1827 AbortChecker::Instance().stopMonitoring(fd);
1828 fdc_table[fd].half_closed = false;
1829 }
1830
2d8c0b1a 1831 fdc_table[fd] = fdc_t(fd);
62e76326 1832
83704487 1833 statCounter.syscalls.sock.closes++;
62e76326 1834
88bfe092 1835 PROF_stop(comm_close);
a46d2c0e 1836 /* When an fd closes, give accept() a chance, if need be */
1837
1838 if (fdNFree() >= RESERVED_FD)
1839 AcceptLimiter::Instance().kick();
090089c4 1840}
1841
090089c4 1842/* Send a udp datagram to specified TO_ADDR. */
b8d8561b 1843int
5df61230 1844comm_udp_sendto(int fd,
62e76326 1845
1846 const struct sockaddr_in *to_addr,
1847 int addr_len,
1848 const void *buf,
1849 int len)
090089c4 1850{
5df61230 1851 int x;
88bfe092 1852 PROF_start(comm_udp_sendto);
83704487 1853 statCounter.syscalls.sock.sendtos++;
62e76326 1854
5df61230 1855 x = sendto(fd, buf, len, 0, (struct sockaddr *) to_addr, addr_len);
88bfe092 1856 PROF_stop(comm_udp_sendto);
62e76326 1857
2d8c0b1a 1858 if (x >= 0)
1859 return x;
1860
17d51783 1861#ifdef _SQUID_LINUX_
62e76326 1862
2d8c0b1a 1863 if (ECONNREFUSED != errno)
17d51783 1864#endif
62e76326 1865
2d8c0b1a 1866 debug(50, 1) ("comm_udp_sendto: FD %d, %s, port %d: %s\n",
1867 fd,
1868 inet_ntoa(to_addr->sin_addr),
1869 (int) htons(to_addr->sin_port),
1870 xstrerror());
62e76326 1871
2d8c0b1a 1872 return COMM_ERROR;
090089c4 1873}
1874
b8d8561b 1875void
582b6456 1876comm_add_close_handler(int fd, PF * handler, void *data)
30a4f2a8 1877{
e6ccf245 1878 close_handler *newHandler = (close_handler *)memPoolAlloc(conn_close_pool); /* AAA */
cddc721b 1879 close_handler *c;
a3d5953d 1880 debug(5, 5) ("comm_add_close_handler: FD %d, handler=%p, data=%p\n",
62e76326 1881 fd, handler, data);
1882
29b8d8d6 1883 for (c = fd_table[fd].closeHandler; c; c = c->next)
62e76326 1884 assert(c->handler != handler || c->data != data);
1885
e6ccf245 1886 newHandler->handler = handler;
62e76326 1887
e6ccf245 1888 newHandler->data = cbdataReference(data);
62e76326 1889
e6ccf245 1890 newHandler->next = fd_table[fd].closeHandler;
62e76326 1891
e6ccf245 1892 fd_table[fd].closeHandler = newHandler;
30a4f2a8 1893}
1894
b8d8561b 1895void
582b6456 1896comm_remove_close_handler(int fd, PF * handler, void *data)
090089c4 1897{
f1dc9b30 1898 close_handler *p;
1899 close_handler *last = NULL;
30a4f2a8 1900 /* Find handler in list */
e869f2bd 1901 debug(5, 5) ("comm_remove_close_handler: FD %d, handler=%p, data=%p\n",
62e76326 1902 fd, handler, data);
1903
29b8d8d6 1904 for (p = fd_table[fd].closeHandler; p != NULL; last = p, p = p->next)
62e76326 1905 if (p->handler == handler && p->data == data)
1906 break; /* This is our handler */
1907
f88211e8 1908 assert(p != NULL);
62e76326 1909
30a4f2a8 1910 /* Remove list entry */
1911 if (last)
62e76326 1912 last->next = p->next;
30a4f2a8 1913 else
62e76326 1914 fd_table[fd].closeHandler = p->next;
1915
fa80a8ef 1916 cbdataReferenceDone(p->data);
62e76326 1917
fa80a8ef 1918 memPoolFree(conn_close_pool, p);
30a4f2a8 1919}
090089c4 1920
b8d8561b 1921static void
1922commSetNoLinger(int fd)
30a4f2a8 1923{
62e76326 1924
30a4f2a8 1925 struct linger L;
090089c4 1926 L.l_onoff = 0; /* off */
1927 L.l_linger = 0;
62e76326 1928
30a4f2a8 1929 if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &L, sizeof(L)) < 0)
62e76326 1930 debug(50, 0) ("commSetNoLinger: FD %d: %s\n", fd, xstrerror());
1931
58a6c186 1932 fd_table[fd].flags.nolinger = 1;
090089c4 1933}
1934
b8d8561b 1935static void
1936commSetReuseAddr(int fd)
090089c4 1937{
1938 int on = 1;
62e76326 1939
30a4f2a8 1940 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0)
62e76326 1941 debug(50, 1) ("commSetReuseAddr: FD %d: %s\n", fd, xstrerror());
090089c4 1942}
1943
b8d8561b 1944static void
1945commSetTcpRcvbuf(int fd, int size)
f868539a 1946{
1947 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *) &size, sizeof(size)) < 0)
62e76326 1948 debug(50, 1) ("commSetTcpRcvbuf: FD %d, SIZE %d: %s\n",
1949 fd, size, xstrerror());
f868539a 1950}
1951
b8d8561b 1952int
1953commSetNonBlocking(int fd)
30a4f2a8 1954{
731e4d49 1955 int flags;
9e205701 1956 int dummy = 0;
7f6ffd15 1957#ifdef _SQUID_CYGWIN_
62e76326 1958
b05490a8 1959 int nonblocking = TRUE;
62e76326 1960
7f6ffd15 1961 if (fd_table[fd].type != FD_PIPE) {
62e76326 1962 if (ioctl(fd, FIONBIO, &nonblocking) < 0) {
1963 debug(50, 0) ("commSetNonBlocking: FD %d: %s %D\n", fd, xstrerror(), fd_table[fd].type);
1964 return COMM_ERROR;
1965 }
7f6ffd15 1966 } else {
1967#endif
62e76326 1968
1969 if ((flags = fcntl(fd, F_GETFL, dummy)) < 0) {
1970 debug(50, 0) ("FD %d: fcntl F_GETFL: %s\n", fd, xstrerror());
1971 return COMM_ERROR;
1972 }
1973
1974 if (fcntl(fd, F_SETFL, flags | SQUID_NONBLOCK) < 0) {
1975 debug(50, 0) ("commSetNonBlocking: FD %d: %s\n", fd, xstrerror());
1976 return COMM_ERROR;
1977 }
1978
7f6ffd15 1979#ifdef _SQUID_CYGWIN_
62e76326 1980
090089c4 1981 }
62e76326 1982
7f6ffd15 1983#endif
58a6c186 1984 fd_table[fd].flags.nonblocking = 1;
62e76326 1985
090089c4 1986 return 0;
1987}
1988
7e3ce7b9 1989int
1990commUnsetNonBlocking(int fd)
1991{
1992 int flags;
1993 int dummy = 0;
62e76326 1994
7e3ce7b9 1995 if ((flags = fcntl(fd, F_GETFL, dummy)) < 0) {
62e76326 1996 debug(50, 0) ("FD %d: fcntl F_GETFL: %s\n", fd, xstrerror());
1997 return COMM_ERROR;
7e3ce7b9 1998 }
62e76326 1999
7e3ce7b9 2000 if (fcntl(fd, F_SETFL, flags & (~SQUID_NONBLOCK)) < 0) {
62e76326 2001 debug(50, 0) ("commUnsetNonBlocking: FD %d: %s\n", fd, xstrerror());
2002 return COMM_ERROR;
7e3ce7b9 2003 }
62e76326 2004
7e3ce7b9 2005 fd_table[fd].flags.nonblocking = 0;
2006 return 0;
2007}
2008
b8d8561b 2009void
2010commSetCloseOnExec(int fd)
3ca60c86 2011{
2012#ifdef FD_CLOEXEC
731e4d49 2013 int flags;
7a18b487 2014 int dummy = 0;
62e76326 2015
c7989865 2016 if ((flags = fcntl(fd, F_GETFL, dummy)) < 0) {
62e76326 2017 debug(50, 0) ("FD %d: fcntl F_GETFL: %s\n", fd, xstrerror());
2018 return;
3ca60c86 2019 }
62e76326 2020
24382924 2021 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
62e76326 2022 debug(50, 0) ("FD %d: set close-on-exec failed: %s\n", fd, xstrerror());
2023
d6827718 2024 fd_table[fd].flags.close_on_exec = 1;
62e76326 2025
3ca60c86 2026#endif
2027}
2028
e90100aa 2029#ifdef TCP_NODELAY
2030static void
2031commSetTcpNoDelay(int fd)
2032{
2033 int on = 1;
62e76326 2034
e90100aa 2035 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on)) < 0)
62e76326 2036 debug(50, 1) ("commSetTcpNoDelay: FD %d: %s\n", fd, xstrerror());
2037
d6827718 2038 fd_table[fd].flags.nodelay = 1;
e90100aa 2039}
62e76326 2040
e90100aa 2041#endif
2042
6a988308 2043
d86b3703 2044void
0673c0ba 2045comm_init(void)
090089c4 2046{
c4b7a5a9 2047 fd_table =(fde *) xcalloc(Squid_MaxFD, sizeof(fde));
2048 fdd_table = (fd_debug_t *)xcalloc(Squid_MaxFD, sizeof(fd_debug_t));
2d8c0b1a 2049 fdc_table = new fdc_t[Squid_MaxFD];
2050
2051 for (int pos = 0; pos < Squid_MaxFD; ++pos)
2052 fdc_table[pos] = fdc_t(pos);
2053
59c4d35b 2054 /* XXX account fd_table */
090089c4 2055 /* Keep a few file descriptors free so that we don't run out of FD's
2056 * after accepting a client but before it opens a socket or a file.
e83892e9 2057 * Since Squid_MaxFD can be as high as several thousand, don't waste them */
0254ee29 2058 RESERVED_FD = XMIN(100, Squid_MaxFD / 4);
2d8c0b1a 2059
28c60158 2060 CBDATA_INIT_TYPE(ConnectStateData);
c4b7a5a9 2061
723123a9 2062 comm_write_pool = memPoolCreate("CommWriteStateData", sizeof(CommWriteStateData));
2d8c0b1a 2063
58cd5bbd 2064 conn_close_pool = memPoolCreate("close_handler", sizeof(close_handler));
090089c4 2065}
2066
30a4f2a8 2067/* Write to FD. */
b8d8561b 2068static void
582b6456 2069commHandleWrite(int fd, void *data)
30a4f2a8 2070{
e6ccf245 2071 CommWriteStateData *state = (CommWriteStateData *)data;
30a4f2a8 2072 int len = 0;
2073 int nleft;
2074
88bfe092 2075 PROF_start(commHandleWrite);
32754419 2076 debug(5, 5) ("commHandleWrite: FD %d: off %ld, sz %ld.\n",
62e76326 2077 fd, (long int) state->offset, (long int) state->size);
30a4f2a8 2078
2079 nleft = state->size - state->offset;
1f7c9178 2080 len = FD_WRITE_METHOD(fd, state->buf + state->offset, nleft);
6a988308 2081 debug(5, 5) ("commHandleWrite: write() returns %d\n", len);
b69f7771 2082 fd_bytes(fd, len, FD_WRITE);
83704487 2083 statCounter.syscalls.sock.writes++;
30a4f2a8 2084
2085 if (len == 0) {
62e76326 2086 /* Note we even call write if nleft == 0 */
2087 /* We're done */
2088
2089 if (nleft != 0)
2090 debug(5, 1) ("commHandleWrite: FD %d: write failure: connection closed with %d bytes remaining.\n", fd, nleft);
2091
2092 CommWriteStateCallbackAndFree(fd, nleft ? COMM_ERROR : COMM_OK);
30a4f2a8 2093 } else if (len < 0) {
62e76326 2094 /* An error */
2095
2096 if (fd_table[fd].flags.socket_eof) {
2097 debug(50, 2) ("commHandleWrite: FD %d: write failure: %s.\n",
2098 fd, xstrerror());
2099 CommWriteStateCallbackAndFree(fd, COMM_ERROR);
2100 } else if (ignoreErrno(errno)) {
2101 debug(50, 10) ("commHandleWrite: FD %d: write failure: %s.\n",
2102 fd, xstrerror());
2103 commSetSelect(fd,
2104 COMM_SELECT_WRITE,
2105 commHandleWrite,
2106 state,
2107 0);
2108 } else {
2109 debug(50, 2) ("commHandleWrite: FD %d: write failure: %s.\n",
2110 fd, xstrerror());
2111 CommWriteStateCallbackAndFree(fd, COMM_ERROR);
2112 }
30a4f2a8 2113 } else {
62e76326 2114 /* A successful write, continue */
2115 state->offset += len;
2116
2117 if (state->offset < (off_t)state->size) {
2118 /* Not done, reinstall the write handler and write some more */
2119 commSetSelect(fd,
2120 COMM_SELECT_WRITE,
2121 commHandleWrite,
2122 state,
2123 0);
2124 } else {
2125 CommWriteStateCallbackAndFree(fd, COMM_OK);
2126 }
30a4f2a8 2127 }
62e76326 2128
88bfe092 2129 PROF_stop(commHandleWrite);
30a4f2a8 2130}
2131
2132
2133
7cd8c414 2134/*
2135 * Queue a write. handler/handler_data are called when the write
2136 * completes, on error, or on file descriptor close.
2137 *
2138 * free_func is used to free the passed buffer when the write has completed.
2139 */
b8d8561b 2140void
d4cb310b 2141comm_old_write(int fd, const char *buf, int size, CWCB * handler, void *handler_data, FREE * free_func)
30a4f2a8 2142{
aa9e2cab 2143 CommWriteStateData *state = fd_table[fd].rwstate;
c4b7a5a9 2144
2145 assert(!fd_table[fd].flags.closing);
2146
a3d5953d 2147 debug(5, 5) ("comm_write: FD %d: sz %d: hndl %p: data %p.\n",
62e76326 2148 fd, size, handler, handler_data);
2149
aa9e2cab 2150 if (NULL != state) {
62e76326 2151 debug(5, 1) ("comm_write: fd_table[%d].rwstate != NULL\n", fd);
2152 memPoolFree(comm_write_pool, state);
2153 fd_table[fd].rwstate = NULL;
6cf028ab 2154 }
62e76326 2155
e6ccf245 2156 fd_table[fd].rwstate = state = (CommWriteStateData *)memPoolAlloc(comm_write_pool);
a2c963ae 2157 state->buf = (char *) buf;
30a4f2a8 2158 state->size = size;
2159 state->offset = 0;
2160 state->handler = handler;
fa80a8ef 2161 state->handler_data = cbdataReference(handler_data);
c0dec081 2162 state->free_func = free_func;
aa9e2cab 2163 commSetSelect(fd, COMM_SELECT_WRITE, commHandleWrite, state, 0);
30a4f2a8 2164}
26a880e2 2165
137ee196 2166/* a wrapper around comm_write to allow for MemBuf to be comm_written in a snap */
cb69b4c7 2167void
d4cb310b 2168comm_old_write_mbuf(int fd, MemBuf mb, CWCB * handler, void *handler_data)
cb69b4c7 2169{
d4cb310b 2170 comm_old_write(fd, mb.buf, mb.size, handler, handler_data, memBufFreeFunc(&mb));
cb69b4c7 2171}
2172
c4b7a5a9 2173
89924214 2174/*
2175 * hm, this might be too general-purpose for all the places we'd
2176 * like to use it.
2177 */
b224ea98 2178int
edd2eb63 2179ignoreErrno(int ierrno)
26a880e2 2180{
603500e7 2181 switch (ierrno) {
62e76326 2182
89924214 2183 case EINPROGRESS:
62e76326 2184
603500e7 2185 case EWOULDBLOCK:
26a880e2 2186#if EAGAIN != EWOULDBLOCK
62e76326 2187
603500e7 2188 case EAGAIN:
26a880e2 2189#endif
62e76326 2190
603500e7 2191 case EALREADY:
62e76326 2192
603500e7 2193 case EINTR:
db494ab8 2194#ifdef ERESTART
62e76326 2195
db494ab8 2196 case ERESTART:
2197#endif
62e76326 2198
2199 return 1;
2200
603500e7 2201 default:
62e76326 2202 return 0;
603500e7 2203 }
62e76326 2204
603500e7 2205 /* NOTREACHED */
26a880e2 2206}
d723bf6b 2207
2208void
2209commCloseAllSockets(void)
2210{
2211 int fd;
2212 fde *F = NULL;
62e76326 2213
d723bf6b 2214 for (fd = 0; fd <= Biggest_FD; fd++) {
62e76326 2215 F = &fd_table[fd];
2216
2217 if (!F->flags.open)
2218 continue;
2219
2220 if (F->type != FD_SOCKET)
2221 continue;
2222
2223 if (F->flags.ipc) /* don't close inter-process sockets */
2224 continue;
2225
2226 if (F->timeout_handler) {
2227 PF *callback = F->timeout_handler;
2228 void *cbdata = NULL;
2229 F->timeout_handler = NULL;
2230 debug(5, 5) ("commCloseAllSockets: FD %d: Calling timeout handler\n",
2231 fd);
2232
2233 if (cbdataReferenceValidDone(F->timeout_data, &cbdata))
2234 callback(fd, cbdata);
2235 } else {
2236 debug(5, 5) ("commCloseAllSockets: FD %d: calling comm_close()\n", fd);
2237 comm_close(fd);
2238 }
d723bf6b 2239 }
2240}
1b3db6d9 2241
2d8c0b1a 2242static bool
2243AlreadyTimedOut(fde *F)
2244{
2245 if (!F->flags.open)
2246 return true;
2247
2248 if (F->timeout == 0)
2249 return true;
2250
2251 if (F->timeout > squid_curtime)
2252 return true;
2253
2254 return false;
2255}
2256
1b3db6d9 2257void
2258checkTimeouts(void)
2259{
2260 int fd;
2261 fde *F = NULL;
2262 PF *callback;
62e76326 2263
1b3db6d9 2264 for (fd = 0; fd <= Biggest_FD; fd++) {
62e76326 2265 F = &fd_table[fd];
2266
2d8c0b1a 2267 if (AlreadyTimedOut(F))
62e76326 2268 continue;
2269
2270 debug(5, 5) ("checkTimeouts: FD %d Expired\n", fd);
2271
2272 if (F->timeout_handler) {
2273 debug(5, 5) ("checkTimeouts: FD %d: Call timeout handler\n", fd);
2274 callback = F->timeout_handler;
2275 F->timeout_handler = NULL;
2276 callback(fd, F->timeout_data);
2277 } else {
2278 debug(5, 5) ("checkTimeouts: FD %d: Forcing comm_close()\n", fd);
2279 comm_close(fd);
2280 }
b5443c04 2281 }
2282}
2283
c4b7a5a9 2284/*
2285 * New-style listen and accept routines
2286 *
2287 * Listen simply registers our interest in an FD for listening,
2288 * and accept takes a callback to call when an FD has been
2289 * accept()ed.
2290 */
2291int
2292comm_listen(int sock)
2293{
2294 int x;
62e76326 2295
c4b7a5a9 2296 if ((x = listen(sock, Squid_MaxFD >> 2)) < 0) {
62e76326 2297 debug(50, 0) ("comm_listen: listen(%d, %d): %s\n",
2298 Squid_MaxFD >> 2,
2299 sock, xstrerror());
2300 return x;
c4b7a5a9 2301 }
62e76326 2302
c4b7a5a9 2303 return sock;
2304}
2305
2d8c0b1a 2306void
2307fdc_t::beginAccepting()
2308{
2309 accept.accept.beginAccepting();
2310}
c4b7a5a9 2311
2d8c0b1a 2312int
2313fdc_t::acceptCount() const
c4b7a5a9 2314{
2d8c0b1a 2315 return accept.accept.acceptCount();
2316}
62e76326 2317
2d8c0b1a 2318void
2319fdc_t::acceptOne(int fd)
2320{
2321 /* If we're out of fds, register an event and return now */
62e76326 2322
2d8c0b1a 2323 if (fdNFree() < RESERVED_FD) {
2324 debug(5, 3) ("comm_accept_try: we're out of fds - deferring io!\n");
2325 eventAdd("comm_accept_check_event", comm_accept_check_event, this,
2326 1000.0 / (double)(accept.accept.check_delay), 1);
2327 accept.accept.finished(true);
2328 return;
2329 }
62e76326 2330
2d8c0b1a 2331 /* Accept a new connection */
2332 int newfd = comm_old_accept(fd, accept.connDetails);
62e76326 2333
2d8c0b1a 2334 /* Check for errors */
2335 if (newfd < 0) {
2336 if (newfd == COMM_NOMESSAGE) {
2337 /* register interest again */
2338 commSetSelect(fd, COMM_SELECT_READ, comm_accept_try, NULL, 0);
2339 accept.accept.finished(true);
62e76326 2340 return;
2341 }
2342
2d8c0b1a 2343 /* A non-recoverable error - register an error callback */
2344 new CommAcceptCallbackData(fd, accept.accept.callback, COMM_ERROR, errno, -1, accept.connDetails);
62e76326 2345
2d8c0b1a 2346 accept.accept.callback = CallBack<IOACB>();
62e76326 2347
2d8c0b1a 2348 accept.accept.finished(true);
62e76326 2349
2d8c0b1a 2350 return;
2351 }
62e76326 2352
2d8c0b1a 2353 accept.accept.doCallback(fd, newfd, COMM_OK, 0, &accept.connDetails);
62e76326 2354
2d8c0b1a 2355 /* If we weren't re-registed, don't bother trying again! */
62e76326 2356
2d8c0b1a 2357 if (accept.accept.callback.handler == NULL)
2358 accept.accept.finished(true);
2359}
62e76326 2360
2d8c0b1a 2361bool
2362AcceptFD::finished() const
2363{
2364 return finished_;
2365}
62e76326 2366
2d8c0b1a 2367void
2368AcceptFD::finished(bool newValue)
2369{
2370 finished_ = newValue;
2371}
62e76326 2372
2d8c0b1a 2373bool
2374AcceptFD::finishedAccepting() const
2375{
2376 return acceptCount() >= MAX_ACCEPT_PER_LOOP || finished();
c4b7a5a9 2377}
2378
2d8c0b1a 2379/*
2380 * This callback is called whenever a filedescriptor is ready
2381 * to dupe itself and fob off an accept()ed connection
2382 */
2383static void
2384comm_accept_try(int fd, void *data)
2385{
2386 assert(fdc_table[fd].active == 1);
2387
2388 fdc_table[fd].beginAccepting();
2389
2390 while (!fdc_table[fd].accept.accept.finishedAccepting())
2391 fdc_table[fd].acceptOne(fd);
2392}
c4b7a5a9 2393
2394/*
2395 * Notes:
2396 * + the current interface will queue _one_ accept per io loop.
2397 * this isn't very optimal and should be revisited at a later date.
2398 */
2399void
2400comm_accept(int fd, IOACB *handler, void *handler_data)
2401{
62e76326 2402 fdc_t *Fc;
c4b7a5a9 2403
62e76326 2404 assert(fd_table[fd].flags.open == 1);
2405 assert(fdc_table[fd].active == 1);
c4b7a5a9 2406
62e76326 2407 /* make sure we're not pending! */
2d8c0b1a 2408 assert(fdc_table[fd].accept.accept.callback.handler == NULL);
c4b7a5a9 2409
62e76326 2410 /* Record our details */
2411 Fc = &fdc_table[fd];
2d8c0b1a 2412 Fc->accept.accept.callback = CallBack<IOACB> (handler, handler_data);
c4b7a5a9 2413
62e76326 2414 /* Kick off the accept */
c4b7a5a9 2415#if OPTIMISTIC_IO
62e76326 2416
2417 comm_accept_try(fd, NULL);
c4b7a5a9 2418#else
62e76326 2419
2420 commSetSelect(fd, COMM_SELECT_READ, comm_accept_try, NULL, 0);
c4b7a5a9 2421#endif
2422}
6cce2334 2423
2424void CommIO::Initialise()
2425{
2426 /* Initialize done pipe signal */
2427 int DonePipe[2];
2428 pipe(DonePipe);
2429 DoneFD = DonePipe[1];
2430 DoneReadFD = DonePipe[0];
2431 fd_open(DonePipe[0], FD_PIPE, "async-io completetion event: main");
2432 fd_open(DonePipe[1], FD_PIPE, "async-io completetion event: threads");
2433 commSetNonBlocking(DonePipe[0]);
2434 commSetNonBlocking(DonePipe[1]);
2435 commSetSelect(DonePipe[0], COMM_SELECT_READ, NULLFDHandler, NULL, 0);
2436 Initialised = true;
2437}
2438
2439bool CommIO::Initialised = false;
2440bool CommIO::DoneSignalled = false;
2441int CommIO::DoneFD = -1;
2442int CommIO::DoneReadFD = -1;
2443
2444void
2445CommIO::FlushPipe()
2446{
2447 char buf[256];
2448 read(DoneReadFD, buf, sizeof(buf));
2449}
2450
2451void
2452CommIO::NULLFDHandler(int fd, void *data)
2453{
2454 FlushPipe();
2455 commSetSelect(fd, COMM_SELECT_READ, NULLFDHandler, NULL, 0);
2456}
2457
2458void
62e76326 2459CommIO::ResetNotifications()
6cce2334 2460{
2461 if (DoneSignalled) {
62e76326 2462 FlushPipe();
2463 DoneSignalled = false;
6cce2334 2464 }
2465}
a46d2c0e 2466
2467AcceptLimiter AcceptLimiter::Instance_;
2468
2469AcceptLimiter &AcceptLimiter::Instance()
2470{
2471 return Instance_;
2472}
2473
2474void
2475AcceptLimiter::defer (int fd, Acceptor::AcceptorFunction *aFunc, void *data)
2476{
2477 Acceptor temp;
2478 temp.theFunction = aFunc;
2479 temp.acceptFD = fd;
2480 temp.theData = data;
2481 deferred.push_back(temp);
2482}
2483
2484void
2485AcceptLimiter::kick()
2486{
2487 if (!deferred.size())
2488 return;
2489
2490 /* Yes, this means the first on is the last off....
2491 * If the list container was a little more friendly, we could sensibly us it.
2492 */
2493 Acceptor temp = deferred.pop_back();
2494
2495 comm_accept (temp.acceptFD, temp.theFunction, temp.theData);
2496}
2497
2498void
2499commMarkHalfClosed(int fd)
2500{
2501 assert (fdc_table[fd].active && !fdc_table[fd].half_closed);
2502 AbortChecker::Instance().monitor(fd);
2503 fdc_table[fd].half_closed = true;
2504}
2505
2506AbortChecker &AbortChecker::Instance() {return Instance_;}
2507
2508AbortChecker AbortChecker::Instance_;
2509
2510void
2511AbortChecker::AbortCheckReader(int fd, char *, size_t size, comm_err_t flag, int xerrno, void *data)
2512{
2513 assert (size == 0);
2514 /* sketch:
2515 * if the read is ok and 0, the conn is still open.
2516 * if the read is a fail, close the conn
2517 */
2518
2519 if (flag != COMM_OK && flag != COMM_ERR_CLOSING) {
2520 debug (5,3) ("AbortChecker::AbortCheckReader: fd %d aborted\n", fd);
2521 comm_close(fd);
2522 }
2523}
2524
2525void
2526AbortChecker::monitor(int fd)
2527{
2528 assert (!contains(fd));
2529
2530 add
2531 (fd);
2532
2533 debug (5,3) ("AbortChecker::monitor: monitoring half closed fd %d for aborts\n", fd);
2534}
2535
2536void
2537AbortChecker::stopMonitoring (int fd)
2538{
2539 assert (contains (fd));
2540
2541 remove
2542 (fd);
2543
2544 debug (5,3) ("AbortChecker::stopMonitoring: stopped monitoring half closed fd %d for aborts\n", fd);
2545}
2546
2547#include "splay.h"
2548void
2549AbortChecker::doIOLoop()
2550{
2551 if (checking) {
2552 /*
2553 fds->walk(RemoveCheck, this);
2554 */
2555 checking = false;
2556 return;
2557 }
2558
2559 if (lastCheck >= squid_curtime)
2560 return;
2561
2562 fds->walk(AddCheck, this);
2563
2564 checking = true;
2565
2566 lastCheck = squid_curtime;
2567}
2568
2569void
2570AbortChecker::AddCheck (int const &fd, void *data)
2571{
2572 AbortChecker *me = (AbortChecker *)data;
2573 me->addCheck(fd);
2574}
2575
2576void
2577AbortChecker::RemoveCheck (int const &fd, void *data)
2578{
2579 AbortChecker *me = (AbortChecker *)data;
2580 me->removeCheck(fd);
2581}
2582
2583
2584int
2585AbortChecker::IntCompare (int const &lhs, int const &rhs)
2586{
2587 return lhs - rhs;
2588}
2589
2590bool
2591AbortChecker::contains (int const fd) const
2592{
2593 fds = fds->splay(fd, IntCompare);
2594
2595 if (splayLastResult != 0)
2596 return false;
2597
2598 return true;
2599}
2600
2601void
2602
2603AbortChecker::remove
2604 (int const fd)
2605{
2606
2607 fds = fds->remove
2608 (fd, IntCompare);
2609}
2610
2611void
2612
2613AbortChecker::add
2614 (int const fd)
2615{
2616 fds = fds->insert (fd, IntCompare);
2617}
2618
2619void
2620AbortChecker::addCheck (int const fd)
2621{
2622 /* assert comm_is_open (fd); */
2623 comm_read(fd, NULL, 0, AbortCheckReader, NULL);
2624}
2625
2626void
2627AbortChecker::removeCheck (int const fd)
2628{
2629 /*
2630 comm_read_cancel(fd, AbortCheckReader, NULL);
2631 */
2632}
2633
2d8c0b1a 2634CommRead::CommRead() : fd(-1), buf(NULL), len(0)
a46d2c0e 2635{}
2636
2637CommRead::CommRead(int fd_, char *buf_, int len_, IOCB *handler_, void *data_)
2d8c0b1a 2638 : fd(fd_), buf(buf_), len(len_), callback(handler_, data_)
a46d2c0e 2639{}
2640
2641DeferredRead::DeferredRead () : theReader(NULL), theContext(NULL), theRead(), cancelled(false)
2642{}
2643
2644DeferredRead::DeferredRead (DeferrableRead *aReader, void *data, CommRead const &aRead) : theReader(aReader), theContext (data), theRead(aRead), cancelled(false)
2645{}
2646
2647DeferredReadManager::~DeferredReadManager()
2648{
2649 flushReads();
2650 assert (deferredReads.empty());
2651}
2652
2653void
2654DeferredReadManager::delayRead(DeferredRead const &aRead)
2655{
2656 debug (5, 3)("Adding deferred read on fd %d\n", aRead.theRead.fd);
2657 List<DeferredRead> *temp = deferredReads.push_back(aRead);
2658 comm_add_close_handler (aRead.theRead.fd, CloseHandler, temp);
2659}
2660
2661void
2662DeferredReadManager::CloseHandler(int fd, void *thecbdata)
2663{
2664 if (!cbdataReferenceValid (thecbdata))
2665 return;
2666
2667 List<DeferredRead> *temp = (List<DeferredRead> *)thecbdata;
2668
2669 temp->element.markCancelled();
2670}
2671
2672DeferredRead
2673DeferredReadManager::popHead(ListContainer<DeferredRead> &deferredReads)
2674{
2675 assert (!deferredReads.empty());
2676
2677 if (!deferredReads.head->element.cancelled)
2678 comm_remove_close_handler(deferredReads.head->element.theRead.fd, CloseHandler, deferredReads.head);
2679
2680 DeferredRead result = deferredReads.pop_front();
2681
2682 return result;
2683}
2684
2685void
2686DeferredReadManager::kickReads(int const count)
2687{
2688 /* if we had List::size() we could consolidate this and flushReads */
2689
33cea91c 2690 if (count < 1) {
a46d2c0e 2691 flushReads();
33cea91c 2692 return;
2693 }
a46d2c0e 2694
2695 size_t remaining = count;
2696
2697 while (!deferredReads.empty() && remaining) {
2698 DeferredRead aRead = popHead(deferredReads);
2699 kickARead(aRead);
2700
2701 if (!aRead.cancelled)
2702 --remaining;
2703 }
2704}
2705
2706void
2707DeferredReadManager::flushReads()
2708{
2709 ListContainer<DeferredRead> reads;
2710 reads = deferredReads;
2711 deferredReads = ListContainer<DeferredRead>();
2712
2713 while (!reads.empty()) {
2714 DeferredRead aRead = popHead(reads);
2715 kickARead(aRead);
2716 }
2717}
2718
2719void
2720DeferredReadManager::kickARead(DeferredRead const &aRead)
2721{
2722 if (aRead.cancelled)
2723 return;
2724
2725 debug (5,3)("Kicking deferred read on fd %d\n", aRead.theRead.fd);
2726
2727 aRead.theReader(aRead.theContext, aRead.theRead);
2728}
2729
2730void
2731DeferredRead::markCancelled()
2732{
2733 cancelled = true;
2734}
2d8c0b1a 2735
2736ConnectionDetail::ConnectionDetail()
2737{
2738 bzero(&me, sizeof(me));
2739 bzero(&peer, sizeof(peer));
2740}