/* static void comm_connect_tryconnect(int fd, void *notused) * Input: The fd, the handler data(unused). * Output: None. * Side-effects: Try and connect with pending connect data for the FD. If * we succeed or get a fatal error, call the callback. * Otherwise, it is still blocking or something, so register * to select for a write event on this FD. */ static void comm_connect_tryconnect(int fd, void *notused) { int retval; fde_t *F = &fd_table[fd]; if(F->connect.callback == NULL) return; /* Try the connect() */ retval = connect(fd, (struct sockaddr *) &fd_table[fd].connect.hostaddr, GET_SS_LEN(fd_table[fd].connect.hostaddr)); /* Error? */ if(retval < 0) { /* * If we get EISCONN, then we've already connect()ed the socket, * which is a good thing. * -- adrian */ if(errno == EISCONN) comm_connect_callback(F->fd, COMM_OK); else if(ignoreErrno(errno)) /* Ignore error? Reschedule */ comm_setselect(F->fd, FDLIST_SERVER, COMM_SELECT_WRITE|COMM_SELECT_RETRY, comm_connect_tryconnect, NULL, 0); else /* Error? Fail with COMM_ERR_CONNECT */ comm_connect_callback(F->fd, COMM_ERR_CONNECT); return; } /* If we get here, we've suceeded, so call with COMM_OK */ comm_connect_callback(F->fd, COMM_OK); }
/* Read from client side and queue it for writing to the server */ static void sslReadClient(int fd, void *data) { SslStateData *sslState = data; int len; assert(fd == sslState->client.fd); debug(26, 3) ("sslReadClient: FD %d, reading %d bytes at offset %d\n", fd, SQUID_TCP_SO_RCVBUF - sslState->client.len, sslState->client.len); Counter.syscalls.sock.reads++; len = read(fd, sslState->client.buf + sslState->client.len, SQUID_TCP_SO_RCVBUF - sslState->client.len); debug(26, 3) ("sslReadClient: FD %d, read %d bytes\n", fd, len); if (len > 0) { fd_bytes(fd, len, FD_READ); kb_incr(&Counter.client_http.kbytes_in, len); sslState->client.len += len; } cbdataLock(sslState); if (len < 0) { debug(50, ECONNRESET == errno ? 3 : 1) ("sslReadClient: FD %d: read failure: %s\n", fd, xstrerror()); if (!ignoreErrno(errno)) comm_close(fd); } else if (len == 0) { comm_close(fd); } if (cbdataValid(sslState)) sslSetSelect(sslState); cbdataUnlock(sslState); }
static int do_comm_select(int msec) { int i; int num, saved_errno; if (epoll_fds == 0) { assert(shutting_down); return COMM_SHUTDOWN; } statCounter.syscalls.polls++; num = epoll_wait(kdpfd, events, MAX_EVENTS, msec); saved_errno = errno; getCurrentTime(); debug(5, 5) ("do_comm_select: %d fds ready\n", num); if (num < 0) { if (ignoreErrno(saved_errno)) return COMM_OK; debug(5, 1) ("comm_select: epoll failure: %s\n", xstrerror()); return COMM_ERROR; } statHistCount(&statCounter.select_fds_hist, num); if (num == 0) return COMM_TIMEOUT; for (i = 0; i < num; i++) { comm_call_handlers(events[i].data.fd, events[i].events & ~EPOLLOUT, events[i].events & ~EPOLLIN); } return COMM_OK; }
static int comm_accept_un(int fd) { int sock; struct sockaddr_un P; socklen_t Slen; Slen = sizeof(P); statCounter.syscalls.sock.accepts++; if ((sock = accept(fd, (struct sockaddr *) &P, &Slen)) < 0) { if (ignoreErrno(errno) || errno == ECONNREFUSED || errno == ECONNABORTED) { debug(191, 5) ("comm_accept_un: FD %d: %s\n", fd, xstrerror()); return COMM_NOMESSAGE; } else if (ENFILE == errno || EMFILE == errno) { debug(191, 3) ("comm_accept_un: FD %d: %s\n", fd, xstrerror()); return COMM_ERROR; } else { debug(191, 1) ("comm_accept_un: FD %d: %s\n", fd, xstrerror()); return COMM_ERROR; } } commSetCloseOnExec(sock); /* fdstat update */ fd_open(sock, FD_SOCKET, "LSCS Request"); commSetNonBlocking(sock); return sock; }
static void idnsReadTcp(int fd, void *data) { ssize_t n; idns_query *q = data; int ns = (q->nsends - 1) % nns; if (!q->tcp_buffer) q->tcp_buffer = memAllocBuf(1024, &q->tcp_buffer_size); statCounter.syscalls.sock.reads++; n = FD_READ_METHOD(q->tcp_socket, q->tcp_buffer + q->tcp_buffer_offset, q->tcp_buffer_size - q->tcp_buffer_offset); if (n < 0 && ignoreErrno(errno)) { commSetSelect(q->tcp_socket, COMM_SELECT_READ, idnsReadTcp, q, 0); return; } if (n <= 0) { debug(78, 1) ("idnsReadTcp: Short response from nameserver %d for %s.\n", ns + 1, q->name); idnsTcpCleanup(q); return; } fd_bytes(fd, n, FD_READ); q->tcp_buffer_offset += n; if (q->tcp_buffer_offset > 2) { unsigned short response_size = ntohs(*(short *) q->tcp_buffer); if (q->tcp_buffer_offset >= response_size + 2) { nameservers[ns].nreplies++; idnsGrokReply(q->tcp_buffer + 2, response_size); return; } if (q->tcp_buffer_size < response_size + 2) q->tcp_buffer = memReallocBuf(q->tcp_buffer, response_size + 2, &q->tcp_buffer_size); } commSetSelect(q->tcp_socket, COMM_SELECT_READ, idnsReadTcp, q, 0); }
static int do_comm_select(int msec) { int i; int num; int fd; struct epoll_event *cevents; if (epoll_fds == 0) { assert(shutting_down); return COMM_SHUTDOWN; } statCounter.syscalls.polls++; num = epoll_wait(kdpfd, events, MAX_EVENTS, msec); if (num < 0) { getCurrentTime(); if (ignoreErrno(errno)) return COMM_OK; debug(5, 1) ("comm_select: epoll failure: %s\n", xstrerror()); return COMM_ERROR; } statHistCount(&statCounter.select_fds_hist, num); if (num == 0) return COMM_TIMEOUT; for (i = 0, cevents = events; i < num; i++, cevents++) { fd = cevents->data.fd; comm_call_handlers(fd, cevents->events & ~EPOLLOUT, cevents->events & ~EPOLLIN); } return COMM_OK; }
void comm_select(unsigned long delay) { int num, i, fd; static struct kevent ke[KE_LENGTH]; struct timespec poll_time; PF *hdl; fde_t *F; /* * remember we are doing NANOseconds here, not micro/milli. God knows * why jlemon used a timespec, but hey, he wrote the interface, not I * -- Adrian */ poll_time.tv_sec = 0; poll_time.tv_nsec = delay * 1000000; num = kevent(kq, kqlst, kqoff, ke, KE_LENGTH, &poll_time); kqoff = 0; while (num < 0 && ignoreErrno(errno)) num = kevent(kq, kqlst, 0, ke, KE_LENGTH, &poll_time); set_time(); for (i = 0; i < num; i++) { fd = (int) ke[i].ident; hdl = NULL; F = &fd_table[fd]; if (ke[i].flags & EV_ERROR) { errno = ke[i].data; /* XXX error == bad! -- adrian */ continue; /* XXX! */ } switch (ke[i].filter) { case EVFILT_READ: if ((hdl = F->read_handler) != NULL) { F->read_handler = NULL; hdl(fd, F->read_data); } case EVFILT_WRITE: if ((hdl = F->write_handler) != NULL) { F->write_handler = NULL; hdl(fd, F->write_data); } default: /* Bad! -- adrian */ break; } } }
static void idnsRead(int fd, void *data) { int *N = &incoming_sockets_accepted; ssize_t len; struct sockaddr_in from; socklen_t from_len; int max = INCOMING_DNS_MAX; static char rbuf[SQUID_UDP_SO_RCVBUF]; int ns; while (max--) { from_len = sizeof(from); memset(&from, '\0', from_len); statCounter.syscalls.sock.recvfroms++; len = recvfrom(fd, rbuf, sizeof(rbuf), 0, (struct sockaddr *) &from, &from_len); if (len == 0) break; if (len < 0) { if (ignoreErrno(errno)) break; #ifdef _SQUID_LINUX_ /* Some Linux systems seem to set the FD for reading and then * return ECONNREFUSED when sendto() fails and generates an ICMP * port unreachable message. */ /* or maybe an EHOSTUNREACH "No route to host" message */ if (errno != ECONNREFUSED && errno != EHOSTUNREACH) #endif debug(50, 1) ("idnsRead: FD %d recvfrom: %s\n", fd, xstrerror()); break; } fd_bytes(DnsSocket, len, FD_READ); assert(N); (*N)++; debug(78, 3) ("idnsRead: FD %d: received %d bytes from %s.\n", fd, (int) len, inet_ntoa(from.sin_addr)); ns = idnsFromKnownNameserver(&from); if (ns >= 0) { nameservers[ns].nreplies++; } else if (Config.onoff.ignore_unknown_nameservers) { static time_t last_warning = 0; if (squid_curtime - last_warning > 60) { debug(78, 1) ("WARNING: Reply from unknown nameserver [%s]\n", inet_ntoa(from.sin_addr)); last_warning = squid_curtime; } continue; } idnsGrokReply(rbuf, len); } if (lru_list.head) commSetSelect(DnsSocket, COMM_SELECT_READ, idnsRead, NULL, 0); }
/* * copied from httpReadReply() * * by the time this is called, the ICAP headers have already * been read. */ void icapReadReply(int fd, void *data) { IcapStateData *icap = data; StoreEntry *entry = icap->respmod.entry; const request_t *request = icap->request; int len; debug(81, 5) ("icapReadReply: FD %d: icap %p.\n", fd, data); if (icap->flags.no_content && !icap->flags.http_server_eof) { //AI return; } if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { comm_close(fd); return; } errno = 0; statCounter.syscalls.sock.reads++; len = memBufRead(fd, &icap->chunk_buf); debug(81, 5) ("icapReadReply: FD %d: len %d.\n", fd, len); if (len > 0) { fd_bytes(fd, len, FD_READ); kb_incr(&statCounter.icap.all.kbytes_in, len); commSetTimeout(fd, Config.Timeout.read, icapReadTimeout, icap); if (icap->chunk_buf.size < icap->chunk_buf.capacity) { *(icap->chunk_buf.buf + icap->chunk_buf.size) = '\0'; debug(81, 9) ("{%s}\n", icap->chunk_buf.buf); } } if (len <= 0) { debug(81, 2) ("icapReadReply: FD %d: read failure: %s.\n", fd, xstrerror()); if (ignoreErrno(errno)) { debug(81, 2) ("icapReadReply: FD %d: ignored errno\n", fd); commSetSelect(fd, COMM_SELECT_READ, icapReadReply, icap, 0); } else if (entry->mem_obj->inmem_hi == 0) { ErrorState *err; debug(81, 2) ("icapReadReply: FD %d: generating error page\n", fd); err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR); err->request = requestLink((request_t *) request); err->xerrno = errno; errorAppendEntry(entry, err); comm_close(fd); } else { debug(81, 2) ("icapReadReply: FD %d: just calling comm_close()\n", fd); comm_close(fd); } return; } if (icapReadReply2(icap) < 0) comm_close(fd); }
/* Writes data from the server buffer to the client side */ static void sslWriteClient(int fd, void *data) { SslStateData *sslState = data; int len; assert(fd == sslState->client.fd); debug(26, 3) ("sslWriteClient: FD %d, %d bytes to write\n", fd, sslState->server.len); Counter.syscalls.sock.writes++; len = write(fd, sslState->server.buf, sslState->server.len); debug(26, 3) ("sslWriteClient: FD %d, %d bytes written\n", fd, len); if (len > 0) { fd_bytes(fd, len, FD_WRITE); kb_incr(&Counter.client_http.kbytes_out, len); assert(len <= sslState->server.len); sslState->server.len -= len; /* increment total object size */ if (sslState->size_ptr) *sslState->size_ptr += len; if (sslState->server.len > 0) { /* we didn't write the whole thing */ xmemmove(sslState->server.buf, sslState->server.buf + len, sslState->server.len); } } cbdataLock(sslState); if (len < 0) { debug(50, ignoreErrno(errno) ? 3 : 1) ("sslWriteClient: FD %d: write failure: %s.\n", fd, xstrerror()); if (!ignoreErrno(errno)) comm_close(fd); } if (cbdataValid(sslState)) sslSetSelect(sslState); cbdataUnlock(sslState); }
static void whoisReadReply(int fd, void *data) { WhoisState *p = data; StoreEntry *entry = p->entry; char *buf = memAllocate(MEM_4K_BUF); MemObject *mem = entry->mem_obj; int len; statCounter.syscalls.sock.reads++; len = FD_READ_METHOD(fd, buf, 4095); buf[len] = '\0'; debug(75, 3) ("whoisReadReply: FD %d read %d bytes\n", fd, len); debug(75, 5) ("{%s}\n", buf); if (len > 0) { if (0 == mem->inmem_hi) { http_reply *reply = mem->reply; http_version_t version; storeBuffer(entry); httpBuildVersion(&version, 1, 0); httpReplySetHeaders(reply, version, HTTP_OK, "Gatewaying", "text/plain", -1, -1, -2); httpReplySwapOut(reply, entry); } fd_bytes(fd, len, FD_READ); kb_incr(&statCounter.server.all.kbytes_in, len); kb_incr(&statCounter.server.http.kbytes_in, len); storeAppend(entry, buf, len); storeBufferFlush(entry); commSetSelect(fd, COMM_SELECT_READ, whoisReadReply, p, Config.Timeout.read); } else if (len < 0) { debug(50, 2) ("whoisReadReply: FD %d: read failure: %s.\n", fd, xstrerror()); if (ignoreErrno(errno)) { commSetSelect(fd, COMM_SELECT_READ, whoisReadReply, p, Config.Timeout.read); } else { ErrorState *err; err = errorCon(ERR_READ_ERROR, HTTP_INTERNAL_SERVER_ERROR, p->fwd->request); err->xerrno = errno; fwdFail(p->fwd, err); comm_close(fd); } } else { storeTimestampsSet(entry); storeBufferFlush(entry); if (!EBIT_TEST(entry->flags, RELEASE_REQUEST)) storeSetPublicKey(entry); fwdComplete(p->fwd); debug(75, 3) ("whoisReadReply: Done: %s\n", storeUrl(entry)); comm_close(fd); } memFree(buf, MEM_4K_BUF); }
/* Read from server side and queue it for writing to the client */ static void sslReadServer(int fd, void *data) { SslStateData *sslState = data; int len; size_t read_sz = SQUID_TCP_SO_RCVBUF - sslState->server.len; assert(fd == sslState->server.fd); debug(26, 3) ("sslReadServer: FD %d, reading %d bytes at offset %d\n", fd, read_sz, sslState->server.len); errno = 0; #if DELAY_POOLS read_sz = delayBytesWanted(sslState->delay_id, 1, read_sz); #endif Counter.syscalls.sock.reads++; len = read(fd, sslState->server.buf + sslState->server.len, read_sz); debug(26, 3) ("sslReadServer: FD %d, read %d bytes\n", fd, len); if (len > 0) { fd_bytes(fd, len, FD_READ); #if DELAY_POOLS delayBytesIn(sslState->delay_id, len); #endif kb_incr(&Counter.server.all.kbytes_in, len); kb_incr(&Counter.server.other.kbytes_in, len); sslState->server.len += len; } cbdataLock(sslState); if (len < 0) { debug(50, ignoreErrno(errno) ? 3 : 1) ("sslReadServer: FD %d: read failure: %s\n", fd, xstrerror()); if (!ignoreErrno(errno)) comm_close(fd); } else if (len == 0) { comm_close(sslState->server.fd); } if (cbdataValid(sslState)) sslSetSelect(sslState); cbdataUnlock(sslState); }
/* Read from FD */ static void diskHandleRead(int fd, void *data) { dread_ctrl *ctrl_dat = data; fde *F = &fd_table[fd]; int len; int rc = DISK_OK; /* * FD < 0 indicates premature close; we just have to free * the state data. */ if (fd < 0) { memFree(ctrl_dat, MEM_DREAD_CTRL); return; } if (F->disk.offset != ctrl_dat->file_offset) { debug(6, 3) ("diskHandleRead: FD %d seeking to offset %d\n", fd, (int) ctrl_dat->file_offset); lseek(fd, ctrl_dat->file_offset, SEEK_SET); /* XXX ignore return? */ statCounter.syscalls.disk.seeks++; F->disk.offset = ctrl_dat->file_offset; } errno = 0; len = FD_READ_METHOD(fd, ctrl_dat->buf, ctrl_dat->req_len); if (len > 0) F->disk.offset += len; statCounter.syscalls.disk.reads++; fd_bytes(fd, len, FD_READ); if (len < 0) { if (ignoreErrno(errno)) { commSetSelect(fd, COMM_SELECT_READ, diskHandleRead, ctrl_dat, 0); return; } debug(50, 1) ("diskHandleRead: FD %d: %s\n", fd, xstrerror()); len = 0; rc = DISK_ERROR; } else if (len == 0) { rc = DISK_EOF; } if (cbdataValid(ctrl_dat->client_data)) ctrl_dat->handler(fd, ctrl_dat->buf, len, rc, ctrl_dat->client_data); cbdataUnlock(ctrl_dat->client_data); memFree(ctrl_dat, MEM_DREAD_CTRL); }
/* void comm_select_fdlist(unsigned long delay) * Input: The maximum time to delay. * Output: None * Side-effects: Deregisters future interest in IO and calls the handlers * if an event occurs for an FD. * Comments: Check all connections for new connections and input data * that is to be processed. Also check for connections with data queued * and whether we can write it out. * Called to do the new-style IO, courtesy of of squid (like most of this * new IO code). This routine handles the stuff we've hidden in * comm_setselect and fd_table[] and calls callbacks for IO ready * events. */ void comm_select(unsigned long delay) { int num, fd, ci, revents; PF *hdl; fde_t *F; /* XXX kill that +1 later ! -- adrian */ while ((num = poll(pollfd_list.pollfds, pollfd_list.maxindex + 1, delay)) < 0 && ignoreErrno(errno)) ; set_time(); if (num == 0) return; /* XXX we *could* optimise by falling out after doing num fds ... * Currently it'd be hard to do, because pollfd_list can be changed * within this loop (by I/O handlers) --adx */ for (ci = 0; ci < pollfd_list.maxindex + 1; ci++) { if (((revents = pollfd_list.pollfds[ci].revents) == 0) || (pollfd_list.pollfds[ci].fd) == -1) continue; fd = pollfd_list.pollfds[ci].fd; F = &fd_table[fd]; if (revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) { hdl = F->read_handler; F->read_handler = NULL; poll_update_pollfds(fd, POLLRDNORM, NULL); if (hdl) hdl(fd, F->read_data); } if (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) { hdl = F->write_handler; F->write_handler = NULL; poll_update_pollfds(fd, POLLWRNORM, NULL); if (hdl) hdl(fd, F->write_data); } } }
int comm_select(unsigned long delay) { int num, i; static struct epoll_event pfd[EPOLL_LENGTH]; num = epoll_wait(ep, pfd, EPOLL_LENGTH, delay); set_time(); if(num < 0 && !ignoreErrno(errno)) { return COMM_ERROR; } if(num == 0) return COMM_OK; for (i = 0; i < num; i++) { PF *hdl; fde_t *F = pfd[i].data.ptr; if(pfd[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR)) { callbacks_called++; hdl = F->read_handler; if(hdl) hdl(F->fd, F->read_data); else ilog(L_WARN, "s_bsd_epoll.c: NULL read handler called"); } if(F->flags.open == 0) { /* Read handler closed us..go on and do something useful */ continue; } if(pfd[i].events & (EPOLLOUT | EPOLLHUP | EPOLLERR)) { callbacks_called++; hdl = F->write_handler; if(hdl) hdl(F->fd, F->write_data); else ilog(L_WARN, "s_bsd_epoll.c: NULL write handler called"); } } return COMM_OK; }
static int do_comm_select(int msec) { int num, saved_errno; struct timeval tv; fd_set readfds; fd_set writefds; fd_set errfds; int fd; if (nreadfds + nwritefds == 0) { assert(shutting_down); return COMM_SHUTDOWN; } memcpy(&readfds, &global_readfds, sizeof(fd_set)); memcpy(&writefds, &global_writefds, sizeof(fd_set)); memcpy(&errfds, &global_writefds, sizeof(fd_set)); tv.tv_sec = msec / 1000; tv.tv_usec = (msec % 1000) * 1000; statCounter.syscalls.selects++; num = select(Biggest_FD + 1, &readfds, &writefds, &errfds, &tv); saved_errno = errno; getCurrentTime(); debug(5, 5) ("do_comm_select: %d fds ready\n", num); if (num < 0) { if (ignoreErrno(saved_errno)) return COMM_OK; debug(5, 1) ("comm_select: select failure: %s\n", xstrerror()); return COMM_ERROR; } statHistCount(&statCounter.select_fds_hist, num); if (num == 0) return COMM_TIMEOUT; for (fd = 0; fd <= Biggest_FD; fd++) { int read_event = FD_ISSET(fd, &readfds); int write_event = FD_ISSET(fd, &writefds) || FD_ISSET(fd, &errfds); if (read_event || write_event) comm_call_handlers(fd, read_event, write_event); } return COMM_OK; }
static int do_comm_select(int msec) { int num; int i; if (nfds == 0) { assert(shutting_down); return COMM_SHUTDOWN; } statCounter.syscalls.selects++; num = poll(pfds, nfds, msec); if (num < 0) { getCurrentTime(); if (ignoreErrno(errno)) return COMM_OK; debug(5, 1) ("comm_select: poll failure: %s\n", xstrerror()); return COMM_ERROR; } statHistCount(&statCounter.select_fds_hist, num); if (num == 0) return COMM_TIMEOUT; for (i = nfds - 1; num > 0 && i >= 0; i--) { struct pollfd *pfd = &pfds[i]; short read_event, write_event; if (!pfd->revents) continue; read_event = pfd->revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR); write_event = pfd->revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR); pfd->revents = 0; comm_call_handlers(pfd->fd, read_event, write_event); num--; } return COMM_OK; }
static void whoisReadReply(int fd, void *data) { WhoisState *p = data; StoreEntry *entry = p->entry; char *buf = memAllocate(MEM_4K_BUF); MemObject *mem = entry->mem_obj; int len; statCounter.syscalls.sock.reads++; len = FD_READ_METHOD(fd, buf, 4095); buf[len] = '\0'; debug(75, 3) ("whoisReadReply: FD %d read %d bytes\n", fd, len); debug(75, 5) ("{%s}\n", buf); if (len > 0) { if (0 == mem->inmem_hi) mem->reply->sline.status = HTTP_OK; fd_bytes(fd, len, FD_READ); kb_incr(&statCounter.server.all.kbytes_in, len); kb_incr(&statCounter.server.http.kbytes_in, len); storeAppend(entry, buf, len); commSetSelect(fd, COMM_SELECT_READ, whoisReadReply, p, Config.Timeout.read); } else if (len < 0) { debug(50, 2) ("whoisReadReply: FD %d: read failure: %s.\n", fd, xstrerror()); if (ignoreErrno(errno)) { commSetSelect(fd, COMM_SELECT_READ, whoisReadReply, p, Config.Timeout.read); } else if (mem->inmem_hi == 0) { ErrorState *err; err = errorCon(ERR_READ_ERROR, HTTP_INTERNAL_SERVER_ERROR); err->xerrno = errno; fwdFail(p->fwd, err); comm_close(fd); } else { comm_close(fd); } } else { fwdComplete(p->fwd); debug(75, 3) ("whoisReadReply: Done: %s\n", storeUrl(entry)); comm_close(fd); } memFree(buf, MEM_4K_BUF); }
static void lscsAccept(int sock, void *data) { int fd = -1; // fde *F; ConnStateData *connState = NULL; int max = INCOMING_HTTP_MAX; commSetSelect(sock, COMM_SELECT_READ, lscsAccept, data, 0); while (max-- && !httpAcceptDefer(sock, NULL)) { if ((fd = comm_accept_un(sock)) < 0) { if (!ignoreErrno(errno)) debug(191, 1) ("lscsAccept: FD %d: accept failure: %s\n", sock, xstrerror()); break; } commSetSelect(fd, COMM_SELECT_READ, clientRecvFd, connState, 0); } }
/* static void comm_connect_tryconnect(int fd, void *notused) * Input: The fd, the handler data(unused). * Output: None. * Side-effects: Try and connect with pending connect data for the FD. If * we succeed or get a fatal error, call the callback. * Otherwise, it is still blocking or something, so register * to select for a write event on this FD. */ static void comm_connect_tryconnect(fde_t *fd, void *notused) { int retval; /* This check is needed or re-entrant s_bsd_* like sigio break it. */ if (fd->connect.callback == NULL) return; /* Try the connect() */ retval = connect(fd->fd, (struct sockaddr *) &fd->connect.hostaddr, fd->connect.hostaddr.ss_len); /* Error? */ if (retval < 0) { #ifdef _WIN32 errno = WSAGetLastError(); #endif /* * If we get EISCONN, then we've already connect()ed the socket, * which is a good thing. * -- adrian */ if (errno == EISCONN) comm_connect_callback(fd, COMM_OK); else if (ignoreErrno(errno)) /* Ignore error? Reschedule */ comm_setselect(fd, COMM_SELECT_WRITE, comm_connect_tryconnect, NULL, 0); else /* Error? Fail with COMM_ERR_CONNECT */ comm_connect_callback(fd, COMM_ERR_CONNECT); return; } /* If we get here, we've suceeded, so call with COMM_OK */ comm_connect_callback(fd, COMM_OK); }
int comm_select(unsigned long delay) { int num, i; static struct kevent ke[KE_LENGTH]; struct timespec poll_time; /* * remember we are doing NANOseconds here, not micro/milli. God knows * why jlemon used a timespec, but hey, he wrote the interface, not I * -- Adrian */ poll_time.tv_sec = delay / 1000; poll_time.tv_nsec = (delay % 1000) * 1000000; for (;;) { num = kevent(kq, kqlst, kqoff, ke, KE_LENGTH, &poll_time); kqoff = 0; if(num >= 0) break; if(ignoreErrno(errno)) break; set_time(); return COMM_ERROR; /* NOTREACHED */ } set_time(); if(num == 0) return COMM_OK; /* No error.. */ for (i = 0; i < num; i++) { int fd = (int) ke[i].ident; PF *hdl = NULL; fde_t *F = &fd_table[fd]; if(ke[i].flags & EV_ERROR) { errno = ke[i].data; /* XXX error == bad! -- adrian */ continue; /* XXX! */ } switch (ke[i].filter) { case EVFILT_READ: if((hdl = F->read_handler) != NULL) { F->read_handler = NULL; hdl(fd, F->read_data); } break; case EVFILT_WRITE: if((hdl = F->write_handler) != NULL) { F->write_handler = NULL; hdl(fd, F->write_data); } break; default: /* Bad! -- adrian */ break; } } return COMM_OK; }
/* int comm_select(unsigned long delay) * Input: The maximum time to delay. * Output: Returns -1 on error, 0 on success. * Side-effects: Deregisters future interest in IO and calls the handlers * if an event occurs for an FD. * Comments: Check all connections for new connections and input data * that is to be processed. Also check for connections with data queued * and whether we can write it out. * Called to do the new-style IO, courtesy of of squid (like most of this * new IO code). This routine handles the stuff we've hidden in * comm_setselect and fd_table[] and calls callbacks for IO ready * events. */ int comm_select(unsigned long delay) { int num = 0; int revents = 0; int sig; int fd; int ci; PF *hdl; fde_t *F; struct siginfo si; struct timespec timeout; timeout.tv_sec = 0; timeout.tv_nsec = 1000000 * delay; for (;;) { if (!sigio_is_screwed) { if ((sig = sigtimedwait(&our_sigset, &si, &timeout)) > 0) { if (sig == SIGIO) { ilog(L_WARN, "Kernel RT Signal queue overflowed. Is /proc/sys/kernel/rtsig-max too small?"); sigio_is_screwed = 1; break; } fd = si.si_fd; pollfd_list.pollfds[fd].revents |= si.si_band; revents = pollfd_list.pollfds[fd].revents; num++; F = &fd_table[fd]; set_time(); if (revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) { callbacks_called++; hdl = F->read_handler; F->read_handler = NULL; poll_update_pollfds(fd, POLLIN, NULL); if (hdl) hdl(fd, F->read_data); } if (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) { callbacks_called++; hdl = F->write_handler; F->write_handler = NULL; poll_update_pollfds(fd, POLLOUT, NULL); if (hdl) hdl(fd, F->write_data); } } else break; } else break; } if (!sigio_is_screwed) /* We don't need to proceed */ { set_time(); return 0; } for (;;) { if (sigio_is_screwed) { signal(sigio_signal, SIG_IGN); signal(sigio_signal, SIG_DFL); sigio_is_screwed = 0; } num = poll(pollfd_list.pollfds, pollfd_list.maxindex + 1, 0); if (num >= 0) break; if (ignoreErrno(errno)) continue; /* error! */ set_time(); return -1; /* NOTREACHED */ } /* update current time again, eww.. */ set_time(); if (num == 0) return 0; /* XXX we *could* optimise by falling out after doing num fds ... */ for (ci = 0; ci < pollfd_list.maxindex + 1; ci++) { if (((revents = pollfd_list.pollfds[ci].revents) == 0) || (pollfd_list.pollfds[ci].fd) == -1) continue; fd = pollfd_list.pollfds[ci].fd; F = &fd_table[fd]; if (revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) { callbacks_called++; hdl = F->read_handler; F->read_handler = NULL; poll_update_pollfds(fd, POLLIN, NULL); if (hdl) hdl(fd, F->read_data); } if (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) { callbacks_called++; hdl = F->write_handler; F->write_handler = NULL; poll_update_pollfds(fd, POLLOUT, NULL); if (hdl) hdl(fd, F->write_data); } } mask_our_signal(sigio_signal); return 0; }
int comm_select(unsigned long delay) { int num, i; struct pollfd pollfds[POLL_LENGTH]; struct dvpoll dopoll; do { for (;;) { dopoll.dp_timeout = delay; dopoll.dp_nfds = POLL_LENGTH; dopoll.dp_fds = &pollfds[0]; num = ioctl(dpfd, DP_POLL, &dopoll); if(num >= 0) break; if(ignoreErrno(errno)) break; set_time(); return COMM_ERROR; } set_time(); if(num == 0) continue; for (i = 0; i < num; i++) { int fd = dopoll.dp_fds[i].fd; PF *hdl = NULL; fde_t *F = &fd_table[fd]; if((dopoll.dp_fds[i].revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) && (dopoll.dp_fds[i].events & (POLLRDNORM | POLLIN))) { if((hdl = F->read_handler) != NULL) { F->read_handler = NULL; hdl(fd, F->read_data); /* * this call used to be with a NULL pointer, BUT * in the devpoll case we only want to update the * poll set *if* the handler changes state (active -> * NULL or vice versa.) */ devpoll_update_events(fd, COMM_SELECT_READ, F->read_handler); } else ilog(L_NOTICE, "comm_select: Unhandled read event: fdmask: %x\n", fdmask[fd]); } if((dopoll.dp_fds[i].revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) && (dopoll.dp_fds[i].events & (POLLWRNORM | POLLOUT))) { if((hdl = F->write_handler) != NULL) { F->write_handler = NULL; hdl(fd, F->write_data); /* See above similar code in the read case */ devpoll_update_events(fd, COMM_SELECT_WRITE, F->write_handler); } else ilog(L_NOTICE, "comm_select: Unhandled write event: fdmask: %x\n", fdmask[fd]); } if(dopoll.dp_fds[i].revents & POLLNVAL) { ilog(L_NOTICE, "revents was Invalid for %d\n", fd); } } return COMM_OK; } while (0); /* XXX Get here, we broke! */ return 0; }
void icpHandleUdp(int sock, void *data) { int *N = &incoming_sockets_accepted; struct sockaddr_in from; socklen_t from_len; LOCAL_ARRAY(char, buf, SQUID_UDP_SO_RCVBUF); int len; int icp_version; int max = INCOMING_ICP_MAX; commSetSelect(sock, COMM_SELECT_READ, icpHandleUdp, NULL, 0); while (max--) { from_len = sizeof(from); memset(&from, '\0', from_len); statCounter.syscalls.sock.recvfroms++; len = recvfrom(sock, buf, SQUID_UDP_SO_RCVBUF - 1, 0, (struct sockaddr *) &from, &from_len); if (len == 0) break; if (len < 0) { if (ignoreErrno(errno)) break; #ifdef _SQUID_LINUX_ /* Some Linux systems seem to set the FD for reading and then * return ECONNREFUSED when sendto() fails and generates an ICMP * port unreachable message. */ /* or maybe an EHOSTUNREACH "No route to host" message */ if (errno != ECONNREFUSED && errno != EHOSTUNREACH) #endif debug(50, 1) ("icpHandleUdp: FD %d recvfrom: %s\n", sock, xstrerror()); break; } (*N)++; icpCount(buf, RECV, (size_t) len, 0); buf[len] = '\0'; debug(12, 4) ("icpHandleUdp: FD %d: received %d bytes from %s.\n", sock, len, inet_ntoa(from.sin_addr)); #ifdef ICP_PACKET_DUMP icpPktDump(buf); #endif if (len < sizeof(icp_common_t)) { debug(12, 4) ("icpHandleUdp: Ignoring too-small UDP packet\n"); break; } icp_version = (int) buf[1]; /* cheat! */ if (icp_version == ICP_VERSION_2) icpHandleIcpV2(sock, from, buf, len); else if (icp_version == ICP_VERSION_3) icpHandleIcpV3(sock, from, buf, len); else debug(12, 1) ("WARNING: Unused ICP version %d received from %s:%d\n", icp_version, inet_ntoa(from.sin_addr), ntohs(from.sin_port)); } }
TruncateOp::TruncateOp(bool newopen_file) { this->open_file = newopen_file; // it's possible that we lost a race and some other proc already removed ignoreErrno(-ENOENT); }
int comm_select(unsigned long delay) { int num; int fd; PF *hdl; fde_t *F; struct timeval to; /* Copy over the read/write sets so we don't have to rebuild em */ memcpy(&tmpreadfds, &select_readfds, sizeof(fd_set)); memcpy(&tmpwritefds, &select_writefds, sizeof(fd_set)); for (;;) { to.tv_sec = 0; to.tv_usec = delay * 1000; num = select(highest_fd + 1, &tmpreadfds, &tmpwritefds, NULL, &to); if(num >= 0) break; if(ignoreErrno(errno)) continue; set_time(); /* error! */ return -1; /* NOTREACHED */ } set_time(); if(num == 0) return 0; /* XXX we *could* optimise by falling out after doing num fds ... */ for (fd = 0; fd < highest_fd + 1; fd++) { F = &fd_table[fd]; if(FD_ISSET(fd, &tmpreadfds)) { hdl = F->read_handler; F->read_handler = NULL; if(hdl) hdl(fd, F->read_data); } if(F->flags.open == 0) continue; /* Read handler closed us..go on */ if(FD_ISSET(fd, &tmpwritefds)) { hdl = F->write_handler; F->write_handler = NULL; if(hdl) hdl(fd, F->write_data); } if(F->read_handler == NULL) select_update_selectfds(fd, COMM_SELECT_READ, NULL); if(F->write_handler == NULL) select_update_selectfds(fd, COMM_SELECT_WRITE, NULL); } return 0; }
/* * read_pptp_header * * Reads a packet from a file descriptor and determines whether it is a * valid PPTP Control Message. If a valid PPTP Control Message is detected * it extracts the Control Message type from the packet header. * * args: clientFd (IN) - Clients file descriptor. * packet (OUT) - Packet we read from the client. * pptp_ctrl_type (OUT) - PPTP Control Message type of the packet. * * retn: Number of bytes read on success. * -1 on retryable error. * 0 on error to exit on. */ ssize_t read_pptp_header(int clientFd, unsigned char *packet, int *pptp_ctrl_type) { ssize_t bytes_ttl, bytes_this; /* quantities read (total and this read) */ u_int16_t length; /* length of this packet */ struct pptp_header *header; /* the received header */ static char *buffer = NULL; /* buffer between calls */ static int buffered = 0; /* size of buffer */ *pptp_ctrl_type = 0; /* initialise return arg */ /* read any previously buffered data */ if (buffered) { memcpy(packet, buffer, buffered); free(buffer); buffer = NULL; bytes_ttl = buffered; buffered = 0; if (pptpctrl_debug) syslog(LOG_DEBUG, "CTRL: Read in previous incomplete ctrl packet"); } else bytes_ttl = 0; /* try and get the length in */ if (bytes_ttl < 2) { bytes_this = read(clientFd, packet + bytes_ttl, 2 - bytes_ttl); switch (bytes_this) { case -1: if (ignoreErrno(errno)) { /* re-tryable error, re-buffer and return */ if (bytes_ttl) { buffered = bytes_ttl; buffer = malloc(bytes_ttl); if (!buffer) return(0); memcpy(buffer, packet, bytes_ttl); } syslog(LOG_ERR, "CTRL: Error reading ctrl packet length (bytes_ttl=%lu): %s", (unsigned long) bytes_ttl, strerror(errno)); return -1; } /* FALLTHRU */ case 0: syslog(LOG_ERR, "CTRL: EOF or bad error reading ctrl packet length."); return 0; default: bytes_ttl += bytes_this; /* Not enough data to proceed */ if (bytes_ttl == 1) { buffered = bytes_ttl; buffer = malloc(bytes_ttl); if (!buffer) return(0); memcpy(buffer, packet, bytes_ttl); if (pptpctrl_debug) syslog(LOG_DEBUG, "CTRL: Incomplete ctrl packet length, retry later"); return -1; } } } /* OK, we have (at least) the first 2 bytes, and there is data waiting * * length includes the header, so a length less than 2 is someone * trying to hack into us or a badly corrupted packet. * Why not require length to be at least 10? Since we later cast * packet to struct pptp_header and use at least the 10 first bytes.. * Thanks to Timo Sirainen for mentioning this. */ length = htons(*(u_int16_t *) packet); if (length <= 10 || length > PPTP_MAX_CTRL_PCKT_SIZE) { syslog(LOG_ERR, "CTRL: 11 < Control packet (length=%d) < " "PPTP_MAX_CTRL_PCKT_SIZE (%d)", length, PPTP_MAX_CTRL_PCKT_SIZE); /* we loose sync (unless we malloc something big, which isn't a good * idea - potential DoS) so we must close connection (draft states that * if you loose sync you must close the control connection immediately) */ return 0; } /* Now read the actual control packet */ bytes_this = read(clientFd, packet + bytes_ttl, length - bytes_ttl); switch (bytes_this) { case -1: if(ignoreErrno(errno)) { /* re-tryable error, re-buffer and return */ if (bytes_ttl) { buffered = bytes_ttl; buffer = malloc(bytes_ttl); if (!buffer) return(0); memcpy(buffer, packet, bytes_ttl); } syslog(LOG_ERR, "CTRL: Error reading ctrl packet (bytes_ttl=%lu,length=%d): %s", (unsigned long) bytes_ttl, length, strerror(errno)); return -1; } /* FALLTHRU */ case 0: syslog(LOG_ERR, "CTRL: EOF or bad error reading ctrl packet."); return 0; default: bytes_ttl += bytes_this; /* not enough data to proceed */ if (bytes_ttl != length) { buffered = bytes_ttl; buffer = malloc(bytes_ttl); if (!buffer) return(0); memcpy(buffer, packet, bytes_ttl); if (pptpctrl_debug) syslog(LOG_DEBUG, "CTRL: Incomplete ctrl packet, retry later"); return -1; } } /* We got one :-) */ /* Cast the packet into the PPTP Control Message format */ header = (struct pptp_header *) packet; /* Packet sanity check on magic cookie */ if (ntohl(header->magic) != PPTP_MAGIC_COOKIE) { /* Oops! Not a valid Control Message */ syslog(LOG_ERR, "CTRL: Bad magic cookie - lost syncronization, closing control connection."); /* draft states loss of syncronization must result in * immediate closing of the control connection */ return 0; } /* Woohoo! Looks like we got a valid PPTP packet */ *pptp_ctrl_type = (int) (ntohs(header->ctrl_type)); if (pptpctrl_debug) syslog(LOG_DEBUG, "CTRL: Received PPTP Control Message (type: %d)", *pptp_ctrl_type); return bytes_ttl; }
/* void comm_select(unsigned long delay) * Input: The maximum time to delay. * Output: None * Side-effects: Deregisters future interest in IO and calls the handlers * if an event occurs for an FD. * Comments: Check all connections for new connections and input data * that is to be processed. Also check for connections with data queued * and whether we can write it out. * Called to do the new-style IO, courtesy of squid (like most of this * new IO code). This routine handles the stuff we've hidden in * comm_setselect and fd_table[] and calls callbacks for IO ready * events. */ void comm_select(unsigned long delay) { int revents = 0, sig, fd; PF *hdl; fde_t *F; struct siginfo si; struct timespec timeout; timeout.tv_sec = 0; timeout.tv_nsec = 1000000 * delay; sig = sigtimedwait(&our_sigset, &si, &timeout); set_time(); if (sig != SIGIO) { if (sig > 0) { fd = si.si_fd; pollfd_list.pollfds[fd].revents |= si.si_band; revents = pollfd_list.pollfds[fd].revents; F = &fd_table[fd]; if (revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) { hdl = F->read_handler; F->read_handler = NULL; poll_update_pollfds(fd, POLLIN, NULL); if (hdl) hdl(fd, F->read_data); } if (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) { hdl = F->write_handler; F->write_handler = NULL; poll_update_pollfds(fd, POLLOUT, NULL); if (hdl) hdl(fd, F->write_data); } } return; } /* RT signal queue overflowed.. */ if (CurrentTime - last_rtsigqo_warning >= 30) { ilog(L_WARN, "Kernel RT Signal queue overflowed. " "Is /proc/sys/kernel/rtsig-max too small?"); last_rtsigqo_warning = CurrentTime; } signal(SIGIO_SIGNAL, SIG_IGN); signal(SIGIO_SIGNAL, SIG_DFL); /* ..try polling instead */ { int num, ci; while ((num = poll(pollfd_list.pollfds, pollfd_list.maxindex + 1, 0)) < 0 && ignoreErrno(errno)) ; /* update current time again, eww.. */ set_time(); if (num > 0) { /* XXX we *could* optimise by falling out after doing num fds ... */ for (ci = 0; ci < pollfd_list.maxindex + 1; ci++) { if (((revents = pollfd_list.pollfds[ci].revents) == 0) || (pollfd_list.pollfds[ci].fd) == -1) continue; fd = pollfd_list.pollfds[ci].fd; F = &fd_table[fd]; if (revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) { hdl = F->read_handler; F->read_handler = NULL; poll_update_pollfds(fd, POLLIN, NULL); if (hdl) hdl(fd, F->read_data); } if (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) { hdl = F->write_handler; F->write_handler = NULL; poll_update_pollfds(fd, POLLOUT, NULL); if (hdl) hdl(fd, F->write_data); } } } } mask_our_signal(SIGIO_SIGNAL); }
/* write handler */ static void diskHandleWrite(int fd, void *notused) { int len = 0; fde *F = &fd_table[fd]; struct _fde_disk *fdd = &F->disk; dwrite_q *q = fdd->write_q; int status = DISK_OK; int do_callback; int do_close; if (NULL == q) return; debug(6, 3) ("diskHandleWrite: FD %d\n", fd); F->flags.write_daemon = 0; assert(fdd->write_q != NULL); assert(fdd->write_q->len > fdd->write_q->buf_offset); debug(6, 3) ("diskHandleWrite: FD %d writing %d bytes\n", fd, (int) (fdd->write_q->len - fdd->write_q->buf_offset)); errno = 0; if (fdd->write_q->file_offset != -1) lseek(fd, fdd->write_q->file_offset, SEEK_SET); len = FD_WRITE_METHOD(fd, fdd->write_q->buf + fdd->write_q->buf_offset, fdd->write_q->len - fdd->write_q->buf_offset); debug(6, 3) ("diskHandleWrite: FD %d len = %d\n", fd, len); statCounter.syscalls.disk.writes++; fd_bytes(fd, len, FD_WRITE); if (len < 0) { if (!ignoreErrno(errno)) { status = errno == ENOSPC ? DISK_NO_SPACE_LEFT : DISK_ERROR; debug(50, 1) ("diskHandleWrite: FD %d: disk write error: %s\n", fd, xstrerror()); /* * If there is no write callback, then this file is * most likely something important like a log file, or * an interprocess pipe. Its not a swapfile. We feel * that a write failure on a log file is rather important, * and Squid doesn't otherwise deal with this condition. * So to get the administrators attention, we exit with * a fatal message. */ if (fdd->wrt_handle == NULL) fatal("Write failure -- check your disk space and cache.log"); /* * If there is a write failure, then we notify the * upper layer via the callback, at the end of this * function. Meanwhile, flush all pending buffers * here. Let the upper layer decide how to handle the * failure. This will prevent experiencing multiple, * repeated write failures for the same FD because of * the queued data. */ do { fdd->write_q = q->next; if (q->free_func) (q->free_func) (q->buf); if (q) { memFree(q, MEM_DWRITE_Q); q = NULL; } } while ((q = fdd->write_q)); } len = 0; } if (q != NULL) { /* q might become NULL from write failure above */ q->buf_offset += len; if (q->buf_offset > q->len) debug(50, 1) ("diskHandleWrite: q->buf_offset > q->len (%p,%d, %d, %d FD %d)\n", q, (int) q->buf_offset, (int) q->len, len, fd); assert(q->buf_offset <= q->len); if (q->buf_offset == q->len) { /* complete write */ fdd->write_q = q->next; if (q->free_func) (q->free_func) (q->buf); if (q) { memFree(q, MEM_DWRITE_Q); q = NULL; } } } if (fdd->write_q == NULL) { /* no more data */ fdd->write_q_tail = NULL; } else { /* another block is queued */ diskCombineWrites(fdd); cbdataLock(fdd->wrt_handle_data); commSetSelect(fd, COMM_SELECT_WRITE, diskHandleWrite, NULL, 0); F->flags.write_daemon = 1; } do_close = F->flags.close_request; if (fdd->wrt_handle) { if (fdd->wrt_handle_data == NULL) do_callback = 1; else if (cbdataValid(fdd->wrt_handle_data)) do_callback = 1; else do_callback = 0; if (fdd->wrt_handle_data != NULL) cbdataUnlock(fdd->wrt_handle_data); if (do_callback) { fdd->wrt_handle(fd, status, len, fdd->wrt_handle_data); /* * NOTE, this callback can close the FD, so we must * not touch 'F', 'fdd', etc. after this. */ return; } } if (do_close) file_close(fd); }
/* int comm_select_fdlist(unsigned long delay) * Input: The maximum time to delay. * Output: Returns -1 on error, 0 on success. * Side-effects: Deregisters future interest in IO and calls the handlers * if an event occurs for an FD. * Comments: Check all connections for new connections and input data * that is to be processed. Also check for connections with data queued * and whether we can write it out. * Called to do the new-style IO, courtesy of squid (like most of this * new IO code). This routine handles the stuff we've hidden in * comm_setselect and fd_table[] and calls callbacks for IO ready * events. */ int comm_select(unsigned long delay) { int num; int fd; int ci; unsigned long ndelay; PF *hdl; if(last_count > 0) { empty_count = 0; ndelay = 0; } else { ndelay = ++empty_count * 15000 ; if(ndelay > delay * 1000) ndelay = delay * 1000; } for (;;) { /* XXX kill that +1 later ! -- adrian */ if(ndelay > 0) irc_sleep(ndelay); last_count = num = poll(pollfd_list.pollfds, pollfd_list.maxindex + 1, 0); if(num >= 0) break; if(ignoreErrno(errno)) continue; /* error! */ set_time(); return -1; /* NOTREACHED */ } /* update current time again, eww.. */ set_time(); if(num == 0) return 0; /* XXX we *could* optimise by falling out after doing num fds ... */ for (ci = 0; ci < pollfd_list.maxindex + 1; ci++) { fde_t *F; int revents; if(((revents = pollfd_list.pollfds[ci].revents) == 0) || (pollfd_list.pollfds[ci].fd) == -1) continue; fd = pollfd_list.pollfds[ci].fd; F = &fd_table[fd]; if(revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) { hdl = F->read_handler; F->read_handler = NULL; poll_update_pollfds(fd, POLLRDNORM, NULL); if(hdl) hdl(fd, F->read_data); } if(revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) { hdl = F->write_handler; F->write_handler = NULL; poll_update_pollfds(fd, POLLWRNORM, NULL); if(hdl) hdl(fd, F->write_data); } } return 0; }