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