From 8f888fb1a3469b87e557efad93b293dd36288ba9 Mon Sep 17 00:00:00 2001 From: Sunil Nimmagadda Date: Sat, 14 Sep 2024 12:32:01 +0530 Subject: A HTTP(S), FTP client --- util.c | 215 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 util.c (limited to 'util.c') diff --git a/util.c b/util.c new file mode 100644 index 0000000..463fb8b --- /dev/null +++ b/util.c @@ -0,0 +1,215 @@ +/* + * 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); +} -- cgit v1.2.3