FILE * fetchPutFile(struct url *u, const char *flags) { FILE *f; if (CHECK_FLAG('a')) f = fopen(u->doc, "a"); else f = fopen(u->doc, "w+"); if (f == NULL) _fetch_syserr(); if (u->offset && fseeko(f, u->offset, SEEK_SET) == -1) { fclose(f); _fetch_syserr(); } return (f); }
FILE * fetchXGetFile(struct url *u, struct url_stat *us, const char *flags) { FILE *f; if (us && fetchStatFile(u, us, flags) == -1) return (NULL); f = fopen(u->doc, "r"); if (f == NULL) _fetch_syserr(); if (u->offset && fseeko(f, u->offset, SEEK_SET) == -1) { fclose(f); _fetch_syserr(); } return (f); }
static int _fetch_stat_file(const char *fn, struct url_stat *us) { struct stat sb; us->size = -1; us->atime = us->mtime = 0; if (stat(fn, &sb) == -1) { _fetch_syserr(); return (-1); } us->size = sb.st_size; us->atime = sb.st_atime; us->mtime = sb.st_mtime; return (0); }
/* * Write a vector to a connection w/ timeout * Note: can modify the iovec. */ ssize_t _fetch_writev(conn_t *conn, struct iovec *iov, int iovcnt) { struct timeval now, timeout, wait; fd_set writefds; ssize_t wlen, total; int r; if (fetchTimeout) { FD_ZERO(&writefds); gettimeofday(&timeout, NULL); timeout.tv_sec += fetchTimeout; } total = 0; while (iovcnt > 0) { while (fetchTimeout && !FD_ISSET(conn->sd, &writefds)) { FD_SET(conn->sd, &writefds); gettimeofday(&now, NULL); wait.tv_sec = timeout.tv_sec - now.tv_sec; wait.tv_usec = timeout.tv_usec - now.tv_usec; if (wait.tv_usec < 0) { wait.tv_usec += 1000000; wait.tv_sec--; } if (wait.tv_sec < 0) { errno = WSA(ETIMEDOUT); _fetch_syserr(); return (-1); } errno = 0; r = select(conn->sd + 1, NULL, &writefds, NULL, &wait); if (r == -1) { if (errno == WSA(EINTR) && fetchRestartCalls) continue; return (-1); } } errno = 0; #ifdef WITH_SSL if (conn->ssl != NULL) wlen = SSL_write(conn->ssl, iov->iov_base, iov->iov_len); else #endif #ifdef flagWIN32 wlen = send(conn->sd, iov->iov_base, iov->iov_len, 0); #else wlen = writev(conn->sd, iov, iovcnt); #endif if (wlen == 0) { /* we consider a short write a failure */ errno = EPIPE; _fetch_syserr(); return (-1); } if (wlen < 0) { if (errno == EINTR && fetchRestartCalls) continue; return (-1); } total += wlen; while (iovcnt > 0 && wlen >= (ssize_t)iov->iov_len) { wlen -= iov->iov_len; iov++; iovcnt--; } if (iovcnt > 0) { iov->iov_len -= wlen; iov->iov_base = __DECONST(char *, iov->iov_base) + wlen; } }
/* * Read a character from a connection w/ timeout */ ssize_t _fetch_read(conn_t *conn, char *buf, size_t len) { struct timeval now, timeout, wait; fd_set readfds; ssize_t rlen, total; int r; if (fetchTimeout) { FD_ZERO(&readfds); gettimeofday(&timeout, NULL); timeout.tv_sec += fetchTimeout; } total = 0; while (len > 0) { while (fetchTimeout && !FD_ISSET(conn->sd, &readfds)) { FD_SET(conn->sd, &readfds); gettimeofday(&now, NULL); wait.tv_sec = timeout.tv_sec - now.tv_sec; wait.tv_usec = timeout.tv_usec - now.tv_usec; if (wait.tv_usec < 0) { wait.tv_usec += 1000000; wait.tv_sec--; } if (wait.tv_sec < 0) { errno = WSA(ETIMEDOUT); _fetch_syserr(); return (-1); } errno = 0; r = select(conn->sd + 1, &readfds, NULL, NULL, &wait); if (r == -1) { if (errno == EINTR && fetchRestartCalls) continue; _fetch_syserr(); return (-1); } } #ifdef WITH_SSL if (conn->ssl != NULL) rlen = SSL_read(conn->ssl, buf, len); else #endif #ifdef flagWIN32 rlen = recv(conn->sd, buf, len, 0); #else rlen = read(conn->sd, buf, len); #endif if (rlen == 0) break; if (rlen < 0) { if (errno == EINTR && fetchRestartCalls) continue; return (-1); } len -= rlen; buf += rlen; total += rlen; } return (total); }
/* * Establish a TCP connection to the specified port on the specified host. */ conn_t * _fetch_connect(const char *host, int port, int af, int verbose) { conn_t *conn; char pbuf[10]; const char *bindaddr; struct addrinfo hints, *res, *res0; int sd, err; DEBUG(fprintf(stderr, "---> %s:%d\n", host, port)); if (verbose) _fetch_info("looking up %s", host); /* look up host name and set up socket address structure */ snprintf(pbuf, sizeof(pbuf), "%d", port); memset(&hints, 0, sizeof(hints)); hints.ai_family = af; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; if ((err = getaddrinfo(host, pbuf, &hints, &res0)) != 0) { _netdb_seterr(err); return (NULL); } bindaddr = getenv("FETCH_BIND_ADDRESS"); if (verbose) _fetch_info("connecting to %s:%d", host, port); /* try to connect */ for (sd = -1, res = res0; res; sd = -1, res = res->ai_next) { if ((sd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) continue; if (bindaddr != NULL && *bindaddr != '\0' && _fetch_bind(sd, res->ai_family, bindaddr) != 0) { _fetch_info("failed to bind to '%s'", bindaddr); #ifdef flagWIN32 closesocket(sd); #else close(sd); #endif continue; } if (connect(sd, res->ai_addr, res->ai_addrlen) == 0) break; #ifdef flagWIN32 closesocket(sd); #else close(sd); #endif } freeaddrinfo(res0); if (sd == -1) { _fetch_syserr(); return (NULL); } if ((conn = _fetch_reopen(sd)) == NULL) { _fetch_syserr(); #ifdef flagWIN32 closesocket(sd); #else close(sd); #endif } return (conn); }