static void idnsSendTcpQueryDone(int fd, char *bufnotused, size_t size, int errflag, void *data) { idns_query *q = data; if (size > 0) fd_bytes(fd, size, FD_WRITE); if (errflag == COMM_ERR_CLOSING) return; if (errflag) { idnsTcpCleanup(q); return; } commSetSelect(q->tcp_socket, COMM_SELECT_READ, idnsReadTcp, q, 0); }
/* * Aborts with fatal message if write() returns something other * than its length argument. */ static void logfileWriteWrapper(Logfile * lf, const void *buf, size_t len) { l_stdio_t *ll = (l_stdio_t *) lf->data; size_t s; s = FD_WRITE_METHOD(ll->fd, (char const *) buf, len); fd_bytes(ll->fd, s, FD_WRITE); if (s == len) return; if (!lf->flags.fatal) return; fatalf("logfileWrite (stdio): %s: %s\n", lf->path, xstrerror()); }
static void logfile_mod_udp_write(Logfile * lf, const char *buf, size_t len) { l_udp_t *ll = (l_udp_t *) lf->data; ssize_t s; s = write(ll->fd, (char const *) buf, len); fd_bytes(ll->fd, s, FD_WRITE); #if 0 if (s < 0) { debug(1, 1) ("logfile (udp): got errno %d (%s)\n", errno, xstrerror()); } if (s != len) { debug(1, 1) ("logfile (udp): len %d, wrote %d\n", len, s); } #endif /* We don't worry about network errors for now */ }
/* 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); }
/* This will be called when data is ready to be read from fd. Read until * error or connection closed. */ static void gopherReadReply(int fd, void *data) { GopherStateData *gopherState = data; StoreEntry *entry = gopherState->entry; char *buf = NULL; int len; int clen; int bin; size_t read_sz; #if DELAY_POOLS delay_id delay_id; #endif if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { comm_close(fd); return; } errno = 0; buf = memAllocate(MEM_4K_BUF); read_sz = 4096 - 1; /* leave room for termination */ #if DELAY_POOLS delay_id = delayMostBytesAllowed(entry->mem_obj, &read_sz); #endif /* leave one space for \0 in gopherToHTML */ statCounter.syscalls.sock.reads++; len = FD_READ_METHOD(fd, buf, read_sz); if (len > 0) { fd_bytes(fd, len, FD_READ); #if DELAY_POOLS delayBytesIn(delay_id, len); #endif kb_incr(&statCounter.server.all.kbytes_in, len); kb_incr(&statCounter.server.other.kbytes_in, len); } debug(10, 5) ("gopherReadReply: FD %d read len=%d\n", fd, len); if (len > 0) { commSetTimeout(fd, Config.Timeout.read, NULL, NULL); IOStats.Gopher.reads++; for (clen = len - 1, bin = 0; clen; bin++) clen >>= 1; IOStats.Gopher.read_hist[bin]++; }
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); }
/* This will be called when data is ready to be read from fd. Read until * error or connection closed. */ static void waisReadReply(int fd, void *data) { WaisStateData *waisState = data; LOCAL_ARRAY(char, buf, 4096); StoreEntry *entry = waisState->entry; int len; int clen; int bin; size_t read_sz; #if DELAY_POOLS delay_id delay_id; #endif if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { comm_close(fd); return; } errno = 0; read_sz = 4096; #if DELAY_POOLS delay_id = delayMostBytesAllowed(entry->mem_obj, &read_sz); #endif statCounter.syscalls.sock.reads++; len = FD_READ_METHOD(fd, buf, read_sz); if (len > 0) { fd_bytes(fd, len, FD_READ); #if DELAY_POOLS delayBytesIn(delay_id, len); #endif kb_incr(&statCounter.server.all.kbytes_in, len); kb_incr(&statCounter.server.other.kbytes_in, len); } debug(24, 5) ("waisReadReply: FD %d read len:%d\n", fd, len); if (len > 0) { commSetTimeout(fd, Config.Timeout.read, NULL, NULL); IOStats.Wais.reads++; for (clen = len - 1, bin = 0; clen; bin++) clen >>= 1; IOStats.Wais.read_hist[bin]++; }
static void idnsSendQuery(idns_query * q) { int x; int ns; if (DnsSocket < 0) { debug(78, 1) ("idnsSendQuery: Can't send query, no DNS socket!\n"); return; } /* XXX Select nameserver */ assert(nns > 0); assert(q->lru.next == NULL); assert(q->lru.prev == NULL); idnsTcpCleanup(q); try_again: ns = q->nsends % nns; x = comm_udp_sendto(DnsSocket, &nameservers[ns].S, sizeof(nameservers[ns].S), q->buf, q->sz); q->nsends++; q->queue_t = q->sent_t = current_time; if (x < 0) { debug(50, 1) ("idnsSendQuery: FD %d: sendto: %s\n", DnsSocket, xstrerror()); if (q->nsends % nns != 0) goto try_again; } else { fd_bytes(DnsSocket, x, FD_WRITE); commSetSelect(DnsSocket, COMM_SELECT_READ, idnsRead, NULL, 0); } nameservers[ns].nqueries++; dlinkAdd(q, &q->lru, &lru_list); idnsTickleQueue(); }
/* 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 identReadReply(int fd, void *data) { IdentStateData *state = data; LOCAL_ARRAY(char, buf, BUFSIZ); char *ident = NULL; char *t = NULL; int len = -1; buf[0] = '\0'; statCounter.syscalls.sock.reads++; len = FD_READ_METHOD(fd, buf, BUFSIZ - 1); fd_bytes(fd, len, FD_READ); if (len <= 0) { comm_close(fd); return; } /* * XXX This isn't really very tolerant. It should read until EOL * or EOF and then decode the answer... If the reply is fragmented * then this will fail */ buf[len] = '\0'; if ((t = strchr(buf, '\r'))) *t = '\0'; if ((t = strchr(buf, '\n'))) *t = '\0'; debug(30, 5) ("identReadReply: FD %d: Read '%s'\n", fd, buf); if (strstr(buf, "USERID")) { if ((ident = strrchr(buf, ':'))) { while (xisspace(*++ident)); identCallback(state, ident); } } comm_close(fd); }
/* 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); }
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); }
/* 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); }
static void icapSendRespModDone(int fd, char *bufnotused, size_t size, int errflag, void *data) { IcapStateData *icap = data; ErrorState *err; icap->flags.write_pending = 0; debug(81, 5) ("icapSendRespModDone: FD %d: size %d: errflag %d.\n", fd, size, errflag); if (size > 0) { fd_bytes(fd, size, FD_WRITE); kb_incr(&statCounter.icap.all.kbytes_out, size); } if (errflag == COMM_ERR_CLOSING) return; if (errflag) { err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR); err->xerrno = errno; if (cbdataValid(icap)) err->request = requestLink(icap->request); storeEntryReset(icap->respmod.entry); errorAppendEntry(icap->respmod.entry, err); comm_close(fd); return; } if (EBIT_TEST(icap->respmod.entry->flags, ENTRY_ABORTED)) { debug(81, 3) ("icapSendRespModDone: Entry Aborded\n"); comm_close(fd); return; } if (icap->flags.send_zero_chunk) { debug(81, 3) ("icapSendRespModDone: I'm supposed to send zero chunk now\n"); icap->flags.send_zero_chunk = 0; icapSendRespMod(icap, NULL, 0, 1); return; } if (icap->flags.wait_for_preview_reply || icap->flags.wait_for_reply) { /* Schedule reading the ICAP response */ debug(81, 3) ("icapSendRespModDone: FD %d: commSetSelect on read icapRespModReadReply.\n", fd); commSetSelect(fd, COMM_SELECT_READ, icapRespModReadReply, icap, 0); #if 1 commSetTimeout(fd, Config.Timeout.read, icapReadTimeout, icap); #else if (icap->flags.wait_for_preview_reply || icap->flags.http_server_eof) { /* * Set the read timeout only after all data has been sent * or we are waiting for a preview response * If the ICAP server does not return any data till all data * has been sent, we are likely to hit the timeout for large * HTTP bodies */ commSetTimeout(fd, Config.Timeout.read, icapReadTimeout, icap); } #endif } }
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); }