comm.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:24k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: comm.c,v 1.299 1999/01/18 22:23:32 wessels Exp $
  3.  *
  4.  * DEBUG: section 5     Socket Functions
  5.  * AUTHOR: Harvest Derived
  6.  *
  7.  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
  8.  * ----------------------------------------------------------
  9.  *
  10.  *  Squid is the result of efforts by numerous individuals from the
  11.  *  Internet community.  Development is led by Duane Wessels of the
  12.  *  National Laboratory for Applied Network Research and funded by the
  13.  *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
  14.  *  Duane Wessels and the University of California San Diego.  Please
  15.  *  see the COPYRIGHT file for full details.  Squid incorporates
  16.  *  software developed and/or copyrighted by other sources.  Please see
  17.  *  the CREDITS file for full details.
  18.  *
  19.  *  This program is free software; you can redistribute it and/or modify
  20.  *  it under the terms of the GNU General Public License as published by
  21.  *  the Free Software Foundation; either version 2 of the License, or
  22.  *  (at your option) any later version.
  23.  *  
  24.  *  This program is distributed in the hope that it will be useful,
  25.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  26.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  27.  *  GNU General Public License for more details.
  28.  *  
  29.  *  You should have received a copy of the GNU General Public License
  30.  *  along with this program; if not, write to the Free Software
  31.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  32.  *
  33.  */
  34. #include "squid.h"
  35. #ifdef HAVE_NETINET_TCP_H
  36. #include <netinet/tcp.h>
  37. #endif
  38. #if USE_ASYNC_IO
  39. #define MAX_POLL_TIME 10
  40. #else
  41. #define MAX_POLL_TIME 1000
  42. #endif
  43. typedef struct {
  44.     char *host;
  45.     u_short port;
  46.     struct sockaddr_in S;
  47.     CNCB *callback;
  48.     void *data;
  49.     struct in_addr in_addr;
  50.     int locks;
  51.     int fd;
  52.     int tries;
  53.     int addrcount;
  54.     int connstart;
  55. } ConnectStateData;
  56. /* STATIC */
  57. static int commBind(int s, struct in_addr, u_short port);
  58. static void commSetReuseAddr(int);
  59. static void commSetNoLinger(int);
  60. static void CommWriteStateCallbackAndFree(int fd, int code);
  61. #ifdef TCP_NODELAY
  62. static void commSetTcpNoDelay(int);
  63. #endif
  64. static void commSetTcpRcvbuf(int, int);
  65. static PF commConnectFree;
  66. static PF commConnectHandle;
  67. static PF commHandleWrite;
  68. static IPH commConnectDnsHandle;
  69. static void commConnectCallback(ConnectStateData * cs, int status);
  70. static int commResetFD(ConnectStateData * cs);
  71. static int commRetryConnect(ConnectStateData * cs);
  72. static void
  73. CommWriteStateCallbackAndFree(int fd, int code)
  74. {
  75.     CommWriteStateData *CommWriteState = fd_table[fd].rwstate;
  76.     CWCB *callback = NULL;
  77.     void *data;
  78.     fd_table[fd].rwstate = NULL;
  79.     if (CommWriteState == NULL)
  80. return;
  81.     if (CommWriteState->free_func) {
  82. CommWriteState->free_func(CommWriteState->buf);
  83. CommWriteState->buf = NULL;
  84.     }
  85.     callback = CommWriteState->handler;
  86.     data = CommWriteState->handler_data;
  87.     CommWriteState->handler = NULL;
  88.     if (callback && cbdataValid(data))
  89. callback(fd, CommWriteState->buf, CommWriteState->offset, code, data);
  90.     cbdataUnlock(data);
  91.     safe_free(CommWriteState);
  92. }
  93. /* Return the local port associated with fd. */
  94. u_short
  95. comm_local_port(int fd)
  96. {
  97.     struct sockaddr_in addr;
  98.     socklen_t addr_len = 0;
  99.     fde *F = &fd_table[fd];
  100.     /* If the fd is closed already, just return */
  101.     if (!F->flags.open) {
  102. debug(5, 0) ("comm_local_port: FD %d has been closed.n", fd);
  103. return 0;
  104.     }
  105.     if (F->local_port)
  106. return F->local_port;
  107.     addr_len = sizeof(addr);
  108.     if (getsockname(fd, (struct sockaddr *) &addr, &addr_len)) {
  109. debug(50, 1) ("comm_local_port: Failed to retrieve TCP/UDP port number for socket: FD %d: %sn", fd, xstrerror());
  110. return 0;
  111.     }
  112.     F->local_port = ntohs(addr.sin_port);
  113.     debug(5, 6) ("comm_local_port: FD %d: port %dn", fd, (int) F->local_port);
  114.     return F->local_port;
  115. }
  116. static int
  117. commBind(int s, struct in_addr in_addr, u_short port)
  118. {
  119.     struct sockaddr_in S;
  120.     memset(&S, '', sizeof(S));
  121.     S.sin_family = AF_INET;
  122.     S.sin_port = htons(port);
  123.     S.sin_addr = in_addr;
  124.     Counter.syscalls.sock.binds++;
  125.     if (bind(s, (struct sockaddr *) &S, sizeof(S)) == 0)
  126. return COMM_OK;
  127.     debug(50, 0) ("commBind: Cannot bind socket FD %d to %s:%d: %sn",
  128. s,
  129. S.sin_addr.s_addr == INADDR_ANY ? "*" : inet_ntoa(S.sin_addr),
  130. (int) port,
  131. xstrerror());
  132.     return COMM_ERROR;
  133. }
  134. /* Create a socket. Default is blocking, stream (TCP) socket.  IO_TYPE
  135.  * is OR of flags specified in comm.h. */
  136. int
  137. comm_open(int sock_type,
  138.     int proto,
  139.     struct in_addr addr,
  140.     u_short port,
  141.     int flags,
  142.     const char *note)
  143. {
  144.     int new_socket;
  145.     fde *F = NULL;
  146.     /* Create socket for accepting new connections. */
  147.     Counter.syscalls.sock.sockets++;
  148.     if ((new_socket = socket(AF_INET, sock_type, proto)) < 0) {
  149. /* Increase the number of reserved fd's if calls to socket()
  150.  * are failing because the open file table is full.  This
  151.  * limits the number of simultaneous clients */
  152. switch (errno) {
  153. case ENFILE:
  154. case EMFILE:
  155.     debug(50, 1) ("comm_open: socket failure: %sn", xstrerror());
  156.     break;
  157. default:
  158.     debug(50, 0) ("comm_open: socket failure: %sn", xstrerror());
  159. }
  160. fdAdjustReserved();
  161. return -1;
  162.     }
  163.     /* update fdstat */
  164.     debug(5, 5) ("comm_open: FD %d is a new socketn", new_socket);
  165.     fd_open(new_socket, FD_SOCKET, note);
  166.     F = &fd_table[new_socket];
  167.     if (!(flags & COMM_NOCLOEXEC))
  168. commSetCloseOnExec(new_socket);
  169.     if ((flags & COMM_REUSEADDR))
  170. commSetReuseAddr(new_socket);
  171.     if (port > (u_short) 0) {
  172. commSetNoLinger(new_socket);
  173. if (opt_reuseaddr)
  174.     commSetReuseAddr(new_socket);
  175.     }
  176.     if (addr.s_addr != no_addr.s_addr) {
  177. if (commBind(new_socket, addr, port) != COMM_OK) {
  178.     comm_close(new_socket);
  179.     return -1;
  180. }
  181.     }
  182.     F->local_port = port;
  183.     if (flags & COMM_NONBLOCKING)
  184. if (commSetNonBlocking(new_socket) == COMM_ERROR)
  185.     return -1;
  186. #ifdef TCP_NODELAY
  187.     if (sock_type == SOCK_STREAM)
  188. commSetTcpNoDelay(new_socket);
  189. #endif
  190.     if (Config.tcpRcvBufsz > 0 && sock_type == SOCK_STREAM)
  191. commSetTcpRcvbuf(new_socket, Config.tcpRcvBufsz);
  192.     return new_socket;
  193. }
  194. /*
  195.  * NOTE: set the listen queue to Squid_MaxFD/4 and rely on the kernel to      
  196.  * impose an upper limit.  Solaris' listen(3n) page says it has   
  197.  * no limit on this parameter, but sys/socket.h sets SOMAXCONN 
  198.  * to 5.  HP-UX currently has a limit of 20.  SunOS is 5 and
  199.  * OSF 3.0 is 8.
  200.  */
  201. int
  202. comm_listen(int sock)
  203. {
  204.     int x;
  205.     if ((x = listen(sock, Squid_MaxFD >> 2)) < 0) {
  206. debug(50, 0) ("comm_listen: listen(%d, %d): %sn",
  207.     Squid_MaxFD >> 2,
  208.     sock, xstrerror());
  209. return x;
  210.     }
  211.     return sock;
  212. }
  213. void
  214. commConnectStart(int fd, const char *host, u_short port, CNCB * callback, void *data)
  215. {
  216.     ConnectStateData *cs = xcalloc(1, sizeof(ConnectStateData));
  217.     debug(5, 3) ("commConnectStart: FD %d, %s:%dn", fd, host, (int) port);
  218.     cbdataAdd(cs, cbdataXfree, 0);
  219.     cs->fd = fd;
  220.     cs->host = xstrdup(host);
  221.     cs->port = port;
  222.     cs->callback = callback;
  223.     cs->data = data;
  224.     cbdataLock(cs->data);
  225.     comm_add_close_handler(fd, commConnectFree, cs);
  226.     cs->locks++;
  227.     ipcache_nbgethostbyname(host, commConnectDnsHandle, cs);
  228. }
  229. static void
  230. commConnectDnsHandle(const ipcache_addrs * ia, void *data)
  231. {
  232.     ConnectStateData *cs = data;
  233.     assert(cs->locks == 1);
  234.     cs->locks--;
  235.     if (ia == NULL) {
  236. debug(5, 3) ("commConnectDnsHandle: Unknown host: %sn", cs->host);
  237. if (!dns_error_message) {
  238.     dns_error_message = "Unknown DNS error";
  239.     debug(5, 1) ("commConnectDnsHandle: Bad dns_error_messagen");
  240. }
  241. assert(dns_error_message != NULL);
  242. commConnectCallback(cs, COMM_ERR_DNS);
  243. return;
  244.     }
  245.     assert(ia->cur < ia->count);
  246.     cs->in_addr = ia->in_addrs[ia->cur];
  247.     ipcacheCycleAddr(cs->host, NULL);
  248.     cs->addrcount = ia->count;
  249.     cs->connstart = squid_curtime;
  250.     commConnectHandle(cs->fd, cs);
  251. }
  252. static void
  253. commConnectCallback(ConnectStateData * cs, int status)
  254. {
  255.     CNCB *callback = cs->callback;
  256.     void *data = cs->data;
  257.     int fd = cs->fd;
  258.     comm_remove_close_handler(fd, commConnectFree, cs);
  259.     cs->callback = NULL;
  260.     cs->data = NULL;
  261.     commSetTimeout(fd, -1, NULL, NULL);
  262.     commConnectFree(fd, cs);
  263.     if (cbdataValid(data))
  264. callback(fd, status, data);
  265.     cbdataUnlock(data);
  266. }
  267. static void
  268. commConnectFree(int fd, void *data)
  269. {
  270.     ConnectStateData *cs = data;
  271.     debug(5, 3) ("commConnectFree: FD %dn", fd);
  272.     if (cs->locks)
  273. ipcacheUnregister(cs->host, cs);
  274.     if (cs->data)
  275. cbdataUnlock(cs->data);
  276.     safe_free(cs->host);
  277.     cbdataFree(cs);
  278. }
  279. /* Reset FD so that we can connect() again */
  280. static int
  281. commResetFD(ConnectStateData * cs)
  282. {
  283.     int fd2;
  284.     if (!cbdataValid(cs->data))
  285. return 0;
  286.     Counter.syscalls.sock.sockets++;
  287.     fd2 = socket(AF_INET, SOCK_STREAM, 0);
  288.     Counter.syscalls.sock.sockets++;
  289.     if (fd2 < 0) {
  290. debug(5, 0) ("commResetFD: socket: %sn", xstrerror());
  291. fdAdjustReserved();
  292. return 0;
  293.     }
  294.     if (dup2(fd2, cs->fd) < 0) {
  295. debug(5, 0) ("commResetFD: dup2: %sn", xstrerror());
  296. fdAdjustReserved();
  297. return 0;
  298.     }
  299.     close(fd2);
  300.     fd_table[cs->fd].flags.called_connect = 0;
  301.     /*
  302.      * yuck, this has assumptions about comm_open() arguments for
  303.      * the original socket
  304.      */
  305.     commSetCloseOnExec(cs->fd);
  306.     if (Config.Addrs.tcp_outgoing.s_addr != no_addr.s_addr) {
  307. if (commBind(cs->fd, Config.Addrs.tcp_outgoing, 0) != COMM_OK) {
  308.     comm_close(cs->fd);
  309.     return 0;
  310. }
  311.     }
  312.     commSetNonBlocking(cs->fd);
  313. #ifdef TCP_NODELAY
  314.     commSetTcpNoDelay(cs->fd);
  315. #endif
  316.     if (Config.tcpRcvBufsz > 0)
  317. commSetTcpRcvbuf(cs->fd, Config.tcpRcvBufsz);
  318.     return 1;
  319. }
  320. static int
  321. commRetryConnect(ConnectStateData * cs)
  322. {
  323.     assert(cs->addrcount > 0);
  324.     if (cs->addrcount == 1) {
  325. if (cs->tries >= Config.retry.maxtries)
  326.     return 0;
  327. if (squid_curtime - cs->connstart > Config.Timeout.connect)
  328.     return 0;
  329.     } else {
  330. if (cs->tries > cs->addrcount)
  331.     return 0;
  332.     }
  333.     return commResetFD(cs);
  334. }
  335. /* Connect SOCK to specified DEST_PORT at DEST_HOST. */
  336. static void
  337. commConnectHandle(int fd, void *data)
  338. {
  339.     ConnectStateData *cs = data;
  340.     if (cs->S.sin_addr.s_addr == 0) {
  341. cs->S.sin_family = AF_INET;
  342. cs->S.sin_addr = cs->in_addr;
  343. cs->S.sin_port = htons(cs->port);
  344. if (Config.onoff.log_fqdn)
  345.     fqdncache_gethostbyaddr(cs->S.sin_addr, FQDN_LOOKUP_IF_MISS);
  346.     }
  347.     switch (comm_connect_addr(fd, &cs->S)) {
  348.     case COMM_INPROGRESS:
  349. debug(5, 5) ("commConnectHandle: FD %d: COMM_INPROGRESSn", fd);
  350. commSetSelect(fd, COMM_SELECT_WRITE, commConnectHandle, cs, 0);
  351. break;
  352.     case COMM_OK:
  353. ipcacheMarkGoodAddr(cs->host, cs->S.sin_addr);
  354. commConnectCallback(cs, COMM_OK);
  355. break;
  356.     default:
  357. cs->tries++;
  358. ipcacheMarkBadAddr(cs->host, cs->S.sin_addr);
  359. if (Config.onoff.test_reachability)
  360.     netdbDeleteAddrNetwork(cs->S.sin_addr);
  361. if (commRetryConnect(cs)) {
  362.     cs->locks++;
  363.     ipcache_nbgethostbyname(cs->host, commConnectDnsHandle, cs);
  364. } else {
  365.     commConnectCallback(cs, COMM_ERR_CONNECT);
  366. }
  367. break;
  368.     }
  369. }
  370. int
  371. commSetTimeout(int fd, int timeout, PF * handler, void *data)
  372. {
  373.     fde *F;
  374.     debug(5, 3) ("commSetTimeout: FD %d timeout %dn", fd, timeout);
  375.     assert(fd >= 0);
  376.     assert(fd < Squid_MaxFD);
  377.     F = &fd_table[fd];
  378.     assert(F->flags.open);
  379.     if (timeout < 0) {
  380. F->timeout_handler = NULL;
  381. F->timeout_data = NULL;
  382. return F->timeout = 0;
  383.     }
  384.     assert(handler || F->timeout_handler);
  385.     if (handler || data) {
  386. F->timeout_handler = handler;
  387. F->timeout_data = data;
  388.     }
  389.     return F->timeout = squid_curtime + (time_t) timeout;
  390. }
  391. int
  392. comm_connect_addr(int sock, const struct sockaddr_in *address)
  393. {
  394.     int status = COMM_OK;
  395.     fde *F = &fd_table[sock];
  396.     int x;
  397.     int err = 0;
  398.     socklen_t errlen;
  399.     assert(ntohs(address->sin_port) != 0);
  400.     /* Establish connection. */
  401.     errno = 0;
  402.     if (!F->flags.called_connect) {
  403. F->flags.called_connect = 1;
  404. Counter.syscalls.sock.connects++;
  405. x = connect(sock, (struct sockaddr *) address, sizeof(*address));
  406. if (x < 0)
  407.     debug(5, 9) ("connect FD %d: %sn", sock, xstrerror());
  408.     } else {
  409. #if defined(_SQUID_NEWSOS6_)
  410. /* Makoto MATSUSHITA <matusita@ics.es.osaka-u.ac.jp> */
  411. connect(sock, (struct sockaddr *) address, sizeof(*address));
  412. if (errno == EINVAL) {
  413.     errlen = sizeof(err);
  414.     x = getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &errlen);
  415.     if (x >= 0)
  416. errno = x;
  417. }
  418. #else
  419. errlen = sizeof(err);
  420. x = getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &errlen);
  421. if (x == 0)
  422.     errno = err;
  423. #if defined(_SQUID_SOLARIS_)
  424. /*
  425.  * Solaris 2.4's socket emulation doesn't allow you
  426.  * to determine the error from a failed non-blocking
  427.  * connect and just returns EPIPE.  Create a fake
  428.  * error message for connect.   -- fenner@parc.xerox.com
  429.  */
  430. if (x < 0 && errno == EPIPE)
  431.     errno = ENOTCONN;
  432. #endif
  433. #endif
  434.     }
  435.     if (errno == 0 || errno == EISCONN)
  436. status = COMM_OK;
  437.     else if (ignoreErrno(errno))
  438. status = COMM_INPROGRESS;
  439.     else
  440. return COMM_ERROR;
  441.     xstrncpy(F->ipaddr, inet_ntoa(address->sin_addr), 16);
  442.     F->remote_port = ntohs(address->sin_port);
  443.     if (status == COMM_OK) {
  444. debug(5, 10) ("comm_connect_addr: FD %d connected to %s:%dn",
  445.     sock, F->ipaddr, F->remote_port);
  446.     } else if (status == COMM_INPROGRESS) {
  447. debug(5, 10) ("comm_connect_addr: FD %d connection pendingn", sock);
  448.     }
  449.     return status;
  450. }
  451. /* Wait for an incoming connection on FD.  FD should be a socket returned
  452.  * from comm_listen. */
  453. int
  454. comm_accept(int fd, struct sockaddr_in *pn, struct sockaddr_in *me)
  455. {
  456.     int sock;
  457.     struct sockaddr_in P;
  458.     struct sockaddr_in M;
  459.     socklen_t Slen;
  460.     fde *F = NULL;
  461.     Slen = sizeof(P);
  462.     Counter.syscalls.sock.accepts++;
  463.     if ((sock = accept(fd, (struct sockaddr *) &P, &Slen)) < 0) {
  464. if (ignoreErrno(errno)) {
  465.     debug(50, 5) ("comm_accept: FD %d: %sn", fd, xstrerror());
  466.     return COMM_NOMESSAGE;
  467. } else if (ENFILE == errno || EMFILE == errno) {
  468.     debug(50, 3) ("comm_accept: FD %d: %sn", fd, xstrerror());
  469.     return COMM_ERROR;
  470. } else {
  471.     debug(50, 1) ("comm_accept: FD %d: %sn", fd, xstrerror());
  472.     return COMM_ERROR;
  473. }
  474.     }
  475.     if (pn)
  476. *pn = P;
  477.     Slen = sizeof(M);
  478.     memset(&M, '', Slen);
  479.     getsockname(sock, (struct sockaddr *) &M, &Slen);
  480.     if (me)
  481. *me = M;
  482.     commSetCloseOnExec(sock);
  483.     /* fdstat update */
  484.     fd_open(sock, FD_SOCKET, "HTTP Request");
  485.     F = &fd_table[sock];
  486.     xstrncpy(F->ipaddr, inet_ntoa(P.sin_addr), 16);
  487.     F->remote_port = htons(P.sin_port);
  488.     F->local_port = htons(M.sin_port);
  489.     commSetNonBlocking(sock);
  490.     return sock;
  491. }
  492. void
  493. commCallCloseHandlers(int fd)
  494. {
  495.     fde *F = &fd_table[fd];
  496.     close_handler *ch;
  497.     debug(5, 5) ("commCallCloseHandlers: FD %dn", fd);
  498.     while ((ch = F->close_handler) != NULL) {
  499. F->close_handler = ch->next;
  500. debug(5, 5) ("commCallCloseHandlers: ch->handler=%pn", ch->handler);
  501. if (cbdataValid(ch->data))
  502.     ch->handler(fd, ch->data);
  503. cbdataUnlock(ch->data);
  504. safe_free(ch);
  505.     }
  506. }
  507. #if LINGERING_CLOSE
  508. static void
  509. commLingerClose(int fd, void *unused)
  510. {
  511.     LOCAL_ARRAY(char, buf, 1024);
  512.     int n;
  513.     n = read(fd, buf, 1024);
  514.     if (n < 0)
  515. debug(5, 3) ("commLingerClose: FD %d read: %sn", fd, xstrerror());
  516.     comm_close(fd);
  517. }
  518. static void
  519. commLingerTimeout(int fd, void *unused)
  520. {
  521.     debug(5, 3) ("commLingerTimeout: FD %dn", fd);
  522.     comm_close(fd);
  523. }
  524. /*
  525.  * Inspired by apache
  526.  */
  527. void
  528. comm_lingering_close(int fd)
  529. {
  530.     if (shutdown(fd, 1) < 0) {
  531. comm_close(fd);
  532. return;
  533.     }
  534.     fd_note(fd, "lingering close");
  535.     commSetTimeout(fd, 10, commLingerTimeout, NULL);
  536.     commSetSelect(fd, COMM_SELECT_READ, commLingerClose, NULL, 0);
  537. }
  538. #endif
  539. void
  540. comm_close(int fd)
  541. {
  542.     fde *F = NULL;
  543. #if USE_ASYNC_IO
  544.     int doaioclose = 1;
  545. #endif
  546.     debug(5, 5) ("comm_close: FD %dn", fd);
  547.     assert(fd >= 0);
  548.     assert(fd < Squid_MaxFD);
  549.     F = &fd_table[fd];
  550.     if (F->flags.closing)
  551. return;
  552.     if (shutting_down && (!F->flags.open || F->type == FD_FILE))
  553. return;
  554.     assert(F->flags.open);
  555.     assert(F->type != FD_FILE);
  556. #ifdef USE_ASYNC_IO
  557.     if (F->flags.nolinger && F->flags.nonblocking)
  558. doaioclose = 0;
  559. #endif
  560.     F->flags.closing = 1;
  561.     CommWriteStateCallbackAndFree(fd, COMM_ERR_CLOSING);
  562.     commCallCloseHandlers(fd);
  563.     if (F->uses) /* assume persistent connect count */
  564. pconnHistCount(1, F->uses);
  565.     fd_close(fd); /* update fdstat */
  566. #if defined(_SQUID_LINUX_)
  567.     /*
  568.      * michael@metal.iinet.net.au sez close() on
  569.      * network sockets never blocks.
  570.      */
  571.     close(fd);
  572. #elif USE_ASYNC_IO
  573.     if (doaioclose)
  574. aioClose(fd);
  575.     else
  576. close(fd);
  577. #else
  578.     close(fd);
  579. #endif
  580.     Counter.syscalls.sock.closes++;
  581. }
  582. /* Send a udp datagram to specified TO_ADDR. */
  583. int
  584. comm_udp_sendto(int fd,
  585.     const struct sockaddr_in *to_addr,
  586.     int addr_len,
  587.     const void *buf,
  588.     int len)
  589. {
  590.     int x;
  591.     Counter.syscalls.sock.sendtos++;
  592.     x = sendto(fd, buf, len, 0, (struct sockaddr *) to_addr, addr_len);
  593.     if (x < 0) {
  594. #ifdef _SQUID_LINUX_
  595. if (ECONNREFUSED != errno)
  596. #endif
  597.     debug(50, 1) ("comm_udp_sendto: FD %d, %s, port %d: %sn",
  598. fd,
  599. inet_ntoa(to_addr->sin_addr),
  600. (int) htons(to_addr->sin_port),
  601. xstrerror());
  602. return COMM_ERROR;
  603.     }
  604.     return x;
  605. }
  606. void
  607. commSetDefer(int fd, DEFER * func, void *data)
  608. {
  609.     fde *F = &fd_table[fd];
  610.     F->defer_check = func;
  611.     F->defer_data = data;
  612. }
  613. void
  614. commSetSelect(int fd, unsigned int type, PF * handler, void *client_data, time_t timeout)
  615. {
  616.     fde *F = &fd_table[fd];
  617.     assert(fd >= 0);
  618.     assert(F->flags.open);
  619.     debug(5, 5) ("commSetSelect: FD %d type %dn", fd, type);
  620.     if (type & COMM_SELECT_READ) {
  621. F->read_handler = handler;
  622. F->read_data = client_data;
  623. commUpdateReadBits(fd, handler);
  624.     }
  625.     if (type & COMM_SELECT_WRITE) {
  626. F->write_handler = handler;
  627. F->write_data = client_data;
  628. commUpdateWriteBits(fd, handler);
  629.     }
  630.     if (timeout)
  631. F->timeout = squid_curtime + timeout;
  632. }
  633. void
  634. comm_add_close_handler(int fd, PF * handler, void *data)
  635. {
  636.     close_handler *new = xmalloc(sizeof(*new));
  637.     close_handler *c;
  638.     debug(5, 5) ("comm_add_close_handler: FD %d, handler=%p, data=%pn",
  639. fd, handler, data);
  640.     for (c = fd_table[fd].close_handler; c; c = c->next)
  641. assert(c->handler != handler || c->data != data);
  642.     new->handler = handler;
  643.     new->data = data;
  644.     new->next = fd_table[fd].close_handler;
  645.     fd_table[fd].close_handler = new;
  646.     cbdataLock(data);
  647. }
  648. void
  649. comm_remove_close_handler(int fd, PF * handler, void *data)
  650. {
  651.     close_handler *p;
  652.     close_handler *last = NULL;
  653.     /* Find handler in list */
  654.     debug(5, 5) ("comm_remove_close_handler: FD %d, handler=%p, data=%pn",
  655. fd, handler, data);
  656.     for (p = fd_table[fd].close_handler; p != NULL; last = p, p = p->next)
  657. if (p->handler == handler && p->data == data)
  658.     break; /* This is our handler */
  659.     assert(p != NULL);
  660.     /* Remove list entry */
  661.     if (last)
  662. last->next = p->next;
  663.     else
  664. fd_table[fd].close_handler = p->next;
  665.     cbdataUnlock(p->data);
  666.     safe_free(p);
  667. }
  668. static void
  669. commSetNoLinger(int fd)
  670. {
  671.     struct linger L;
  672.     L.l_onoff = 0; /* off */
  673.     L.l_linger = 0;
  674.     if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &L, sizeof(L)) < 0)
  675. debug(50, 0) ("commSetNoLinger: FD %d: %sn", fd, xstrerror());
  676.     fd_table[fd].flags.nolinger = 1;
  677. }
  678. static void
  679. commSetReuseAddr(int fd)
  680. {
  681.     int on = 1;
  682.     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0)
  683. debug(50, 1) ("commSetReuseAddr: FD %d: %sn", fd, xstrerror());
  684. }
  685. static void
  686. commSetTcpRcvbuf(int fd, int size)
  687. {
  688.     if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *) &size, sizeof(size)) < 0)
  689. debug(50, 1) ("commSetTcpRcvbuf: FD %d, SIZE %d: %sn",
  690.     fd, size, xstrerror());
  691. }
  692. int
  693. commSetNonBlocking(int fd)
  694. {
  695.     int flags;
  696.     int dummy = 0;
  697.     if ((flags = fcntl(fd, F_GETFL, dummy)) < 0) {
  698. debug(50, 0) ("FD %d: fcntl F_GETFL: %sn", fd, xstrerror());
  699. return COMM_ERROR;
  700.     }
  701.     if (fcntl(fd, F_SETFL, flags | SQUID_NONBLOCK) < 0) {
  702. debug(50, 0) ("commSetNonBlocking: FD %d: %sn", fd, xstrerror());
  703. return COMM_ERROR;
  704.     }
  705.     fd_table[fd].flags.nonblocking = 1;
  706.     return 0;
  707. }
  708. void
  709. commSetCloseOnExec(int fd)
  710. {
  711. #ifdef FD_CLOEXEC
  712.     int flags;
  713.     int dummy = 0;
  714.     if ((flags = fcntl(fd, F_GETFL, dummy)) < 0) {
  715. debug(50, 0) ("FD %d: fcntl F_GETFL: %sn", fd, xstrerror());
  716. return;
  717.     }
  718.     if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
  719. debug(50, 0) ("FD %d: set close-on-exec failed: %sn", fd, xstrerror());
  720. #endif
  721. }
  722. #ifdef TCP_NODELAY
  723. static void
  724. commSetTcpNoDelay(int fd)
  725. {
  726.     int on = 1;
  727.     if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on)) < 0)
  728. debug(50, 1) ("commSetTcpNoDelay: FD %d: %sn", fd, xstrerror());
  729. }
  730. #endif
  731. void
  732. comm_init(void)
  733. {
  734.     fd_table = xcalloc(Squid_MaxFD, sizeof(fde));
  735.     /* XXX account fd_table */
  736.     /* Keep a few file descriptors free so that we don't run out of FD's
  737.      * after accepting a client but before it opens a socket or a file.
  738.      * Since Squid_MaxFD can be as high as several thousand, don't waste them */
  739.     RESERVED_FD = XMIN(100, Squid_MaxFD / 4);
  740. }
  741. /* Write to FD. */
  742. static void
  743. commHandleWrite(int fd, void *data)
  744. {
  745.     CommWriteStateData *state = data;
  746.     int len = 0;
  747.     int nleft;
  748.     debug(5, 5) ("commHandleWrite: FD %d: off %d, sz %d.n",
  749. fd, (int) state->offset, state->size);
  750.     nleft = state->size - state->offset;
  751.     len = write(fd, state->buf + state->offset, nleft);
  752.     debug(5, 5) ("commHandleWrite: write() returns %dn", len);
  753.     fd_bytes(fd, len, FD_WRITE);
  754.     Counter.syscalls.sock.writes++;
  755.     if (len == 0) {
  756. /* Note we even call write if nleft == 0 */
  757. /* We're done */
  758. if (nleft != 0)
  759.     debug(5, 1) ("commHandleWrite: FD %d: write failure: connection closed with %d bytes remaining.n", fd, nleft);
  760. CommWriteStateCallbackAndFree(fd, nleft ? COMM_ERROR : COMM_OK);
  761.     } else if (len < 0) {
  762. /* An error */
  763. if (fd_table[fd].flags.socket_eof) {
  764.     debug(50, 2) ("commHandleWrite: FD %d: write failure: %s.n",
  765. fd, xstrerror());
  766.     CommWriteStateCallbackAndFree(fd, COMM_ERROR);
  767. } else if (ignoreErrno(errno)) {
  768.     debug(50, 10) ("commHandleWrite: FD %d: write failure: %s.n",
  769. fd, xstrerror());
  770.     commSetSelect(fd,
  771. COMM_SELECT_WRITE,
  772. commHandleWrite,
  773. state,
  774. 0);
  775. } else {
  776.     debug(50, 2) ("commHandleWrite: FD %d: write failure: %s.n",
  777. fd, xstrerror());
  778.     CommWriteStateCallbackAndFree(fd, COMM_ERROR);
  779. }
  780.     } else {
  781. /* A successful write, continue */
  782. state->offset += len;
  783. if (state->offset < state->size) {
  784.     /* Not done, reinstall the write handler and write some more */
  785.     commSetSelect(fd,
  786. COMM_SELECT_WRITE,
  787. commHandleWrite,
  788. state,
  789. 0);
  790. } else {
  791.     CommWriteStateCallbackAndFree(fd, COMM_OK);
  792. }
  793.     }
  794. }
  795. /* Select for Writing on FD, until SIZE bytes are sent.  Call
  796.  * * HANDLER when complete. */
  797. void
  798. comm_write(int fd, char *buf, int size, CWCB * handler, void *handler_data, FREE * free_func)
  799. {
  800.     CommWriteStateData *state = fd_table[fd].rwstate;
  801.     debug(5, 5) ("comm_write: FD %d: sz %d: hndl %p: data %p.n",
  802. fd, size, handler, handler_data);
  803.     if (NULL != state) {
  804. debug(5, 1) ("comm_write: fd_table[%d].rwstate != NULLn", fd);
  805. safe_free(state);
  806. fd_table[fd].rwstate = NULL;
  807.     }
  808.     assert(state == NULL);
  809.     fd_table[fd].rwstate = state = xcalloc(1, sizeof(CommWriteStateData));
  810.     state->buf = buf;
  811.     state->size = size;
  812.     state->offset = 0;
  813.     state->handler = handler;
  814.     state->handler_data = handler_data;
  815.     state->free_func = free_func;
  816.     cbdataLock(handler_data);
  817. #ifdef OPTIMISTIC_IO
  818.     commHandleWrite(fd, state);
  819. #else
  820.     commSetSelect(fd, COMM_SELECT_WRITE, commHandleWrite, state, 0);
  821. #endif
  822. }
  823. /* a wrapper around comm_write to allow for MemBuf to be comm_written in a snap */
  824. void
  825. comm_write_mbuf(int fd, MemBuf mb, CWCB * handler, void *handler_data)
  826. {
  827.     comm_write(fd, mb.buf, mb.size, handler, handler_data, memBufFreeFunc(&mb));
  828. }
  829. /*
  830.  * hm, this might be too general-purpose for all the places we'd
  831.  * like to use it.
  832.  */
  833. int
  834. ignoreErrno(int ierrno)
  835. {
  836.     switch (ierrno) {
  837.     case EINPROGRESS:
  838.     case EWOULDBLOCK:
  839. #if EAGAIN != EWOULDBLOCK
  840.     case EAGAIN:
  841. #endif
  842.     case EALREADY:
  843.     case EINTR:
  844. #ifdef ERESTART
  845.     case ERESTART:
  846. #endif
  847. return 1;
  848.     default:
  849. return 0;
  850.     }
  851.     /* NOTREACHED */
  852. }
  853. void
  854. commCloseAllSockets(void)
  855. {
  856.     int fd;
  857.     fde *F = NULL;
  858.     PF *callback;
  859.     for (fd = 0; fd <= Biggest_FD; fd++) {
  860. F = &fd_table[fd];
  861. if (!F->flags.open)
  862.     continue;
  863. if (F->type != FD_SOCKET)
  864.     continue;
  865. if (F->flags.ipc) /* don't close inter-process sockets */
  866.     continue;
  867. if (F->timeout_handler) {
  868.     debug(5, 5) ("commCloseAllSockets: FD %d: Calling timeout handlern",
  869. fd);
  870.     callback = F->timeout_handler;
  871.     F->timeout_handler = NULL;
  872.     callback(fd, F->timeout_data);
  873. } else {
  874.     debug(5, 5) ("commCloseAllSockets: FD %d: calling comm_close()n", fd);
  875.     comm_close(fd);
  876. }
  877.     }
  878. }