/* * Copyright (c) 2015 Sunil Nimmagadda * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include "ftp.h" #include "xmalloc.h" static void tooslow(int); /* * Wait for an asynchronous connect(2) attempt to finish. */ int connect_wait(int s) { struct pollfd pfd[1]; int error = 0; socklen_t len = sizeof(error); pfd[0].fd = s; pfd[0].events = POLLOUT; if (poll(pfd, 1, -1) == -1) return -1; if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len) < 0) return -1; if (error != 0) { errno = error; return -1; } return 0; } static void tooslow(int signo) { dprintf(STDERR_FILENO, "%s: connect taking too long\n", getprogname()); _exit(2); } int tcp_connect(const char *host, const char *port, int timeout) { struct addrinfo hints, *res, *res0; char hbuf[NI_MAXHOST]; const char *cause = NULL; int error, s = -1, save_errno; if (host == NULL) { warnx("hostname missing"); return -1; } memset(&hints, 0, sizeof hints); hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; if ((error = getaddrinfo(host, port, &hints, &res0))) { warnx("%s: %s", host, gai_strerror(error)); return -1; } if (timeout) { (void)signal(SIGALRM, tooslow); alarm(timeout); } for (res = res0; res; res = res->ai_next) { if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof hbuf, NULL, 0, NI_NUMERICHOST) != 0) (void)strlcpy(hbuf, "(unknown)", sizeof hbuf); log_info("Trying %s...\n", hbuf); s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s == -1) { cause = "socket"; continue; } for (error = connect(s, res->ai_addr, res->ai_addrlen); error != 0 && errno == EINTR; error = connect_wait(s)) continue; if (error != 0) { cause = "connect"; save_errno = errno; close(s); errno = save_errno; s = -1; continue; } break; } freeaddrinfo(res0); if (s == -1) { warn("%s", cause); return -1; } if (timeout) { signal(SIGALRM, SIG_DFL); alarm(0); } return s; } void log_info(const char *fmt, ...) { va_list ap; if (verbose == 0) return; va_start(ap, fmt); if (oarg && strcmp(oarg, "-") == 0) vfprintf(stderr, fmt, ap); else vprintf(fmt, ap); va_end(ap); } void log_request(const char *prefix, struct url *url, struct url *proxy) { char *host; int custom_port; if (url->scheme == S_FILE) return; custom_port = strcmp(url->port, url_port_str(url->scheme)) ? 1 : 0; if (url->ip_literal) xasprintf(&host, "[%s]", url->host); else host = xstrdup(url->host); if (proxy) log_info("%s %s//%s%s%s%s" " (via %s//%s%s%s)\n", prefix, url_scheme_str(url->scheme), host, custom_port ? ":" : "", custom_port ? url->port : "", url->path ? url->path : "", /* via proxy part */ (proxy->scheme == S_HTTP) ? "http" : "https", proxy->host, proxy->port ? ":" : "", proxy->port ? proxy->port : ""); else log_info("%s %s//%s%s%s%s\n", prefix, url_scheme_str(url->scheme), host, custom_port ? ":" : "", custom_port ? url->port : "", url->path ? url->path : ""); free(host); } void copy_file(FILE *dst, FILE *src, off_t *offset) { char *tmp_buf; size_t r; tmp_buf = xmalloc(TMPBUF_LEN); while ((r = fread(tmp_buf, 1, TMPBUF_LEN, src)) != 0 && !interrupted) { *offset += r; if (fwrite(tmp_buf, 1, r, dst) != r) err(1, "%s: fwrite", __func__); } if (interrupted) { free(tmp_buf); return; } if (!feof(src)) errx(1, "%s: fread", __func__); free(tmp_buf); }