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