📄 comm.c
字号:
debug(5, 10) ("comm_connect_addr: FD %d connected to %s:%d\n", sock, F->ipaddr, F->remote_port); } else if (status == COMM_INPROGRESS) { debug(5, 10) ("comm_connect_addr: FD %d connection pending\n", sock); } return status;}/* Wait for an incoming connection on FD. FD should be a socket returned * from comm_listen. */intcomm_accept(int fd, struct sockaddr_in *pn, struct sockaddr_in *me){ int sock; struct sockaddr_in P; struct sockaddr_in M; socklen_t Slen; fde *F = NULL; Slen = sizeof(P); Counter.syscalls.sock.accepts++; if ((sock = accept(fd, (struct sockaddr *) &P, &Slen)) < 0) { if (ignoreErrno(errno)) { debug(50, 5) ("comm_accept: FD %d: %s\n", fd, xstrerror()); return COMM_NOMESSAGE; } else if (ENFILE == errno || EMFILE == errno) { debug(50, 3) ("comm_accept: FD %d: %s\n", fd, xstrerror()); return COMM_ERROR; } else { debug(50, 1) ("comm_accept: FD %d: %s\n", fd, xstrerror()); return COMM_ERROR; } } if (pn) *pn = P; Slen = sizeof(M); memset(&M, '\0', Slen); getsockname(sock, (struct sockaddr *) &M, &Slen); if (me) *me = M; commSetCloseOnExec(sock); /* fdstat update */ fd_open(sock, FD_SOCKET, "HTTP Request"); F = &fd_table[sock]; xstrncpy(F->ipaddr, inet_ntoa(P.sin_addr), 16); F->remote_port = htons(P.sin_port); F->local_port = htons(M.sin_port); commSetNonBlocking(sock); return sock;}voidcommCallCloseHandlers(int fd){ fde *F = &fd_table[fd]; close_handler *ch; debug(5, 5) ("commCallCloseHandlers: FD %d\n", fd); while ((ch = F->close_handler) != NULL) { F->close_handler = ch->next; debug(5, 5) ("commCallCloseHandlers: ch->handler=%p\n", ch->handler); if (cbdataValid(ch->data)) ch->handler(fd, ch->data); cbdataUnlock(ch->data); safe_free(ch); }}#if LINGERING_CLOSEstatic voidcommLingerClose(int fd, void *unused){ LOCAL_ARRAY(char, buf, 1024); int n; n = read(fd, buf, 1024); if (n < 0) debug(5, 3) ("commLingerClose: FD %d read: %s\n", fd, xstrerror()); comm_close(fd);}static voidcommLingerTimeout(int fd, void *unused){ debug(5, 3) ("commLingerTimeout: FD %d\n", fd); comm_close(fd);}/* * Inspired by apache */voidcomm_lingering_close(int fd){ if (shutdown(fd, 1) < 0) { comm_close(fd); return; } fd_note(fd, "lingering close"); commSetTimeout(fd, 10, commLingerTimeout, NULL); commSetSelect(fd, COMM_SELECT_READ, commLingerClose, NULL, 0);}#endifvoidcomm_close(int fd){ fde *F = NULL;#if USE_ASYNC_IO int doaioclose = 1;#endif debug(5, 5) ("comm_close: FD %d\n", fd); assert(fd >= 0); assert(fd < Squid_MaxFD); F = &fd_table[fd]; if (F->flags.closing) return; if (shutting_down && (!F->flags.open || F->type == FD_FILE)) return; assert(F->flags.open); assert(F->type != FD_FILE);#ifdef USE_ASYNC_IO if (F->flags.nolinger && F->flags.nonblocking) doaioclose = 0;#endif F->flags.closing = 1; CommWriteStateCallbackAndFree(fd, COMM_ERR_CLOSING); commCallCloseHandlers(fd); if (F->uses) /* assume persistent connect count */ pconnHistCount(1, F->uses); fd_close(fd); /* update fdstat */#if defined(_SQUID_LINUX_) /* * michael@metal.iinet.net.au sez close() on * network sockets never blocks. */ close(fd);#elif USE_ASYNC_IO if (doaioclose) aioClose(fd); else close(fd);#else close(fd);#endif Counter.syscalls.sock.closes++;}/* Send a udp datagram to specified TO_ADDR. */intcomm_udp_sendto(int fd, const struct sockaddr_in *to_addr, int addr_len, const void *buf, int len){ int x; Counter.syscalls.sock.sendtos++; x = sendto(fd, buf, len, 0, (struct sockaddr *) to_addr, addr_len); if (x < 0) {#ifdef _SQUID_LINUX_ if (ECONNREFUSED != errno)#endif debug(50, 1) ("comm_udp_sendto: FD %d, %s, port %d: %s\n", fd, inet_ntoa(to_addr->sin_addr), (int) htons(to_addr->sin_port), xstrerror()); return COMM_ERROR; } return x;}voidcommSetDefer(int fd, DEFER * func, void *data){ fde *F = &fd_table[fd]; F->defer_check = func; F->defer_data = data;}voidcommSetSelect(int fd, unsigned int type, PF * handler, void *client_data, time_t timeout){ fde *F = &fd_table[fd]; assert(fd >= 0); assert(F->flags.open); debug(5, 5) ("commSetSelect: FD %d type %d\n", fd, type); if (type & COMM_SELECT_READ) { F->read_handler = handler; F->read_data = client_data; commUpdateReadBits(fd, handler); } if (type & COMM_SELECT_WRITE) { F->write_handler = handler; F->write_data = client_data; commUpdateWriteBits(fd, handler); } if (timeout) F->timeout = squid_curtime + timeout;}voidcomm_add_close_handler(int fd, PF * handler, void *data){ close_handler *new = xmalloc(sizeof(*new)); close_handler *c; debug(5, 5) ("comm_add_close_handler: FD %d, handler=%p, data=%p\n", fd, handler, data); for (c = fd_table[fd].close_handler; c; c = c->next) assert(c->handler != handler || c->data != data); new->handler = handler; new->data = data; new->next = fd_table[fd].close_handler; fd_table[fd].close_handler = new; cbdataLock(data);}voidcomm_remove_close_handler(int fd, PF * handler, void *data){ close_handler *p; close_handler *last = NULL; /* Find handler in list */ debug(5, 5) ("comm_remove_close_handler: FD %d, handler=%p, data=%p\n", fd, handler, data); for (p = fd_table[fd].close_handler; p != NULL; last = p, p = p->next) if (p->handler == handler && p->data == data) break; /* This is our handler */ assert(p != NULL); /* Remove list entry */ if (last) last->next = p->next; else fd_table[fd].close_handler = p->next; cbdataUnlock(p->data); safe_free(p);}static voidcommSetNoLinger(int fd){ struct linger L; L.l_onoff = 0; /* off */ L.l_linger = 0; if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &L, sizeof(L)) < 0) debug(50, 0) ("commSetNoLinger: FD %d: %s\n", fd, xstrerror()); fd_table[fd].flags.nolinger = 1;}static voidcommSetReuseAddr(int fd){ int on = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0) debug(50, 1) ("commSetReuseAddr: FD %d: %s\n", fd, xstrerror());}static voidcommSetTcpRcvbuf(int fd, int size){ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *) &size, sizeof(size)) < 0) debug(50, 1) ("commSetTcpRcvbuf: FD %d, SIZE %d: %s\n", fd, size, xstrerror());}intcommSetNonBlocking(int fd){ int flags; int dummy = 0; if ((flags = fcntl(fd, F_GETFL, dummy)) < 0) { debug(50, 0) ("FD %d: fcntl F_GETFL: %s\n", fd, xstrerror()); return COMM_ERROR; } if (fcntl(fd, F_SETFL, flags | SQUID_NONBLOCK) < 0) { debug(50, 0) ("commSetNonBlocking: FD %d: %s\n", fd, xstrerror()); return COMM_ERROR; } fd_table[fd].flags.nonblocking = 1; return 0;}voidcommSetCloseOnExec(int fd){#ifdef FD_CLOEXEC int flags; int dummy = 0; if ((flags = fcntl(fd, F_GETFL, dummy)) < 0) { debug(50, 0) ("FD %d: fcntl F_GETFL: %s\n", fd, xstrerror()); return; } if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) debug(50, 0) ("FD %d: set close-on-exec failed: %s\n", fd, xstrerror());#endif}#ifdef TCP_NODELAYstatic voidcommSetTcpNoDelay(int fd){ int on = 1; if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on)) < 0) debug(50, 1) ("commSetTcpNoDelay: FD %d: %s\n", fd, xstrerror());}#endifvoidcomm_init(void){ fd_table = xcalloc(Squid_MaxFD, sizeof(fde)); /* XXX account fd_table */ /* Keep a few file descriptors free so that we don't run out of FD's * after accepting a client but before it opens a socket or a file. * Since Squid_MaxFD can be as high as several thousand, don't waste them */ RESERVED_FD = XMIN(100, Squid_MaxFD / 4);}/* Write to FD. */static voidcommHandleWrite(int fd, void *data){ CommWriteStateData *state = data; int len = 0; int nleft; debug(5, 5) ("commHandleWrite: FD %d: off %d, sz %d.\n", fd, (int) state->offset, state->size); nleft = state->size - state->offset; len = write(fd, state->buf + state->offset, nleft); debug(5, 5) ("commHandleWrite: write() returns %d\n", len); fd_bytes(fd, len, FD_WRITE); Counter.syscalls.sock.writes++; if (len == 0) { /* Note we even call write if nleft == 0 */ /* We're done */ if (nleft != 0) debug(5, 1) ("commHandleWrite: FD %d: write failure: connection closed with %d bytes remaining.\n", fd, nleft); CommWriteStateCallbackAndFree(fd, nleft ? COMM_ERROR : COMM_OK); } else if (len < 0) { /* An error */ if (fd_table[fd].flags.socket_eof) { debug(50, 2) ("commHandleWrite: FD %d: write failure: %s.\n", fd, xstrerror()); CommWriteStateCallbackAndFree(fd, COMM_ERROR); } else if (ignoreErrno(errno)) { debug(50, 10) ("commHandleWrite: FD %d: write failure: %s.\n", fd, xstrerror()); commSetSelect(fd, COMM_SELECT_WRITE, commHandleWrite, state, 0); } else { debug(50, 2) ("commHandleWrite: FD %d: write failure: %s.\n", fd, xstrerror()); CommWriteStateCallbackAndFree(fd, COMM_ERROR); } } else { /* A successful write, continue */ state->offset += len; if (state->offset < state->size) { /* Not done, reinstall the write handler and write some more */ commSetSelect(fd, COMM_SELECT_WRITE, commHandleWrite, state, 0); } else { CommWriteStateCallbackAndFree(fd, COMM_OK); } }}/* Select for Writing on FD, until SIZE bytes are sent. Call * * HANDLER when complete. */voidcomm_write(int fd, char *buf, int size, CWCB * handler, void *handler_data, FREE * free_func){ CommWriteStateData *state = fd_table[fd].rwstate; debug(5, 5) ("comm_write: FD %d: sz %d: hndl %p: data %p.\n", fd, size, handler, handler_data); if (NULL != state) { debug(5, 1) ("comm_write: fd_table[%d].rwstate != NULL\n", fd); safe_free(state); fd_table[fd].rwstate = NULL; } assert(state == NULL); fd_table[fd].rwstate = state = xcalloc(1, sizeof(CommWriteStateData)); state->buf = buf; state->size = size; state->offset = 0; state->handler = handler; state->handler_data = handler_data; state->free_func = free_func; cbdataLock(handler_data);#ifdef OPTIMISTIC_IO commHandleWrite(fd, state);#else commSetSelect(fd, COMM_SELECT_WRITE, commHandleWrite, state, 0);#endif}/* a wrapper around comm_write to allow for MemBuf to be comm_written in a snap */voidcomm_write_mbuf(int fd, MemBuf mb, CWCB * handler, void *handler_data){ comm_write(fd, mb.buf, mb.size, handler, handler_data, memBufFreeFunc(&mb));}/* * hm, this might be too general-purpose for all the places we'd * like to use it. */intignoreErrno(int ierrno){ switch (ierrno) { case EINPROGRESS: case EWOULDBLOCK:#if EAGAIN != EWOULDBLOCK case EAGAIN:#endif case EALREADY: case EINTR:#ifdef ERESTART case ERESTART:#endif return 1; default: return 0; } /* NOTREACHED */}voidcommCloseAllSockets(void){ int fd; fde *F = NULL; PF *callback; for (fd = 0; fd <= Biggest_FD; fd++) { F = &fd_table[fd]; if (!F->flags.open) continue; if (F->type != FD_SOCKET) continue; if (F->flags.ipc) /* don't close inter-process sockets */ continue; if (F->timeout_handler) { debug(5, 5) ("commCloseAllSockets: FD %d: Calling timeout handler\n", fd); callback = F->timeout_handler; F->timeout_handler = NULL; callback(fd, F->timeout_data); } else { debug(5, 5) ("commCloseAllSockets: FD %d: calling comm_close()\n", fd); comm_close(fd); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -