util.c
changeset 0 1d0ce1ebbc72
equal deleted inserted replaced
-1:000000000000 0:1d0ce1ebbc72
       
     1 /*
       
     2  * Copyright (c) 2015 Sunil Nimmagadda <sunil@openbsd.org>
       
     3  *
       
     4  * Permission to use, copy, modify, and distribute this software for any
       
     5  * purpose with or without fee is hereby granted, provided that the above
       
     6  * copyright notice and this permission notice appear in all copies.
       
     7  *
       
     8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
       
     9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
       
    10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
       
    11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
       
    12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
       
    13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
       
    14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
       
    15  */
       
    16 
       
    17 #include <sys/socket.h>
       
    18 
       
    19 #include <err.h>
       
    20 #include <errno.h>
       
    21 #include <netdb.h>
       
    22 #include <poll.h>
       
    23 #include <signal.h>
       
    24 #include <stdarg.h>
       
    25 #include <stdio.h>
       
    26 #include <string.h>
       
    27 #include <stdlib.h>
       
    28 #include <unistd.h>
       
    29 
       
    30 #include "ftp.h"
       
    31 #include "xmalloc.h"
       
    32 
       
    33 static void	tooslow(int);
       
    34 
       
    35 /*
       
    36  * Wait for an asynchronous connect(2) attempt to finish.
       
    37  */
       
    38 int
       
    39 connect_wait(int s)
       
    40 {
       
    41 	struct pollfd pfd[1];
       
    42 	int error = 0;
       
    43 	socklen_t len = sizeof(error);
       
    44 
       
    45 	pfd[0].fd = s;
       
    46 	pfd[0].events = POLLOUT;
       
    47 
       
    48 	if (poll(pfd, 1, -1) == -1)
       
    49 		return -1;
       
    50 	if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
       
    51 		return -1;
       
    52 	if (error != 0) {
       
    53 		errno = error;
       
    54 		return -1;
       
    55 	}
       
    56 	return 0;
       
    57 }
       
    58 
       
    59 static void
       
    60 tooslow(int signo)
       
    61 {
       
    62 	dprintf(STDERR_FILENO, "%s: connect taking too long\n", getprogname());
       
    63 	_exit(2);
       
    64 }
       
    65 
       
    66 int
       
    67 tcp_connect(const char *host, const char *port, int timeout)
       
    68 {
       
    69 	struct addrinfo	 hints, *res, *res0;
       
    70 	char		 hbuf[NI_MAXHOST];
       
    71 	const char	*cause = NULL;
       
    72 	int		 error, s = -1, save_errno;
       
    73 
       
    74 	if (host == NULL) {
       
    75 		warnx("hostname missing");
       
    76 		return -1;
       
    77 	}
       
    78 
       
    79 	memset(&hints, 0, sizeof hints);
       
    80 	hints.ai_family = family;
       
    81 	hints.ai_socktype = SOCK_STREAM;
       
    82 	if ((error = getaddrinfo(host, port, &hints, &res0))) {
       
    83 		warnx("%s: %s", host, gai_strerror(error));
       
    84 		return -1;
       
    85 	}
       
    86 
       
    87 	if (timeout) {
       
    88 		(void)signal(SIGALRM, tooslow);
       
    89 		alarm(timeout);
       
    90 	}
       
    91 
       
    92 	for (res = res0; res; res = res->ai_next) {
       
    93 		if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf,
       
    94 		    sizeof hbuf, NULL, 0, NI_NUMERICHOST) != 0)
       
    95 			(void)strlcpy(hbuf, "(unknown)", sizeof hbuf);
       
    96 
       
    97 		log_info("Trying %s...\n", hbuf);
       
    98 		s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
       
    99 		if (s == -1) {
       
   100 			cause = "socket";
       
   101 			continue;
       
   102 		}
       
   103 
       
   104 		for (error = connect(s, res->ai_addr, res->ai_addrlen);
       
   105 		    error != 0 && errno == EINTR; error = connect_wait(s))
       
   106 			continue;
       
   107 
       
   108 		if (error != 0) {
       
   109 			cause = "connect";
       
   110 			save_errno = errno;
       
   111 			close(s);
       
   112 			errno = save_errno;
       
   113 			s = -1;
       
   114 			continue;
       
   115 		}
       
   116 
       
   117 		break;
       
   118 	}
       
   119 
       
   120 	freeaddrinfo(res0);
       
   121 	if (s == -1) {
       
   122 		warn("%s", cause);
       
   123 		return -1;
       
   124 	}
       
   125 
       
   126 	if (timeout) {
       
   127 		signal(SIGALRM, SIG_DFL);
       
   128 		alarm(0);
       
   129 	}
       
   130 
       
   131 	return s;
       
   132 }
       
   133 
       
   134 void
       
   135 log_info(const char *fmt, ...)
       
   136 {
       
   137 	va_list	ap;
       
   138 
       
   139 	if (verbose == 0)
       
   140 		return;
       
   141 
       
   142 	va_start(ap, fmt);
       
   143 	if (oarg && strcmp(oarg, "-") == 0)
       
   144 		vfprintf(stderr, fmt, ap);
       
   145 	else
       
   146 		vprintf(fmt, ap);
       
   147 
       
   148 	va_end(ap);
       
   149 }
       
   150 
       
   151 void
       
   152 log_request(const char *prefix, struct url *url, struct url *proxy)
       
   153 {
       
   154 	char	*host;
       
   155 	int	 custom_port;
       
   156 
       
   157 	if (url->scheme == S_FILE)
       
   158 		return;
       
   159 
       
   160 	custom_port = strcmp(url->port, url_port_str(url->scheme)) ? 1 : 0;
       
   161 	if (url->ip_literal)
       
   162 		xasprintf(&host, "[%s]", url->host);
       
   163 	else
       
   164 		host = xstrdup(url->host);
       
   165 
       
   166 	if (proxy)
       
   167 		log_info("%s %s//%s%s%s%s"
       
   168 		    " (via %s//%s%s%s)\n",
       
   169 		    prefix,
       
   170 		    url_scheme_str(url->scheme),
       
   171 		    host,
       
   172 		    custom_port ? ":" : "",
       
   173 		    custom_port ? url->port : "",
       
   174 		    url->path ? url->path : "",
       
   175 
       
   176 		    /* via proxy part */
       
   177 		    (proxy->scheme == S_HTTP) ? "http" : "https",
       
   178 		    proxy->host,
       
   179 		    proxy->port ? ":" : "",
       
   180 		    proxy->port ? proxy->port : "");
       
   181 	else
       
   182 		log_info("%s %s//%s%s%s%s\n",
       
   183 		    prefix,
       
   184 		    url_scheme_str(url->scheme),
       
   185 		    host,
       
   186 		    custom_port ? ":" : "",
       
   187 		    custom_port ? url->port : "",
       
   188 		    url->path ? url->path : "");
       
   189 
       
   190 	free(host);
       
   191 }
       
   192 
       
   193 void
       
   194 copy_file(FILE *dst, FILE *src, off_t *offset)
       
   195 {
       
   196 	char	*tmp_buf;
       
   197 	size_t	 r;
       
   198 
       
   199 	tmp_buf = xmalloc(TMPBUF_LEN);
       
   200 	while ((r = fread(tmp_buf, 1, TMPBUF_LEN, src)) != 0 && !interrupted) {
       
   201 		*offset += r;
       
   202 		if (fwrite(tmp_buf, 1, r, dst) != r)
       
   203 			err(1, "%s: fwrite", __func__);
       
   204 	}
       
   205 
       
   206 	if (interrupted) {
       
   207 		free(tmp_buf);
       
   208 		return;
       
   209 	}
       
   210 
       
   211 	if (!feof(src))
       
   212 		errx(1, "%s: fread", __func__);
       
   213 
       
   214 	free(tmp_buf);
       
   215 }