common.c revision 62964
1103285Sikob/*-
2113584Ssimokawa * Copyright (c) 1998 Dag-Erling Co�dan Sm�rgrav
3103285Sikob * All rights reserved.
4103285Sikob *
5103285Sikob * Redistribution and use in source and binary forms, with or without
6103285Sikob * modification, are permitted provided that the following conditions
7103285Sikob * are met:
8103285Sikob * 1. Redistributions of source code must retain the above copyright
9103285Sikob *    notice, this list of conditions and the following disclaimer
10103285Sikob *    in this position and unchanged.
11103285Sikob * 2. Redistributions in binary form must reproduce the above copyright
12103285Sikob *    notice, this list of conditions and the following disclaimer in the
13103285Sikob *    documentation and/or other materials provided with the distribution.
14103285Sikob * 3. The name of the author may not be used to endorse or promote products
15103285Sikob *    derived from this software without specific prior written permission
16103285Sikob *
17103285Sikob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18103285Sikob * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19103285Sikob * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20103285Sikob * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21103285Sikob * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22103285Sikob * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23103285Sikob * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24103285Sikob * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25103285Sikob * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26103285Sikob * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27103285Sikob *
28103285Sikob * $FreeBSD: head/lib/libfetch/common.c 62964 2000-07-11 18:07:09Z des $
29103285Sikob */
30103285Sikob
31103285Sikob#include <sys/param.h>
32103285Sikob#include <sys/socket.h>
33103285Sikob#include <sys/time.h>
34103285Sikob#include <netinet/in.h>
35103285Sikob
36103285Sikob#include <errno.h>
37103285Sikob#include <netdb.h>
38103285Sikob#include <stdarg.h>
39103285Sikob#include <stdlib.h>
40103285Sikob#include <stdio.h>
41103285Sikob#include <string.h>
42103285Sikob#include <unistd.h>
43103285Sikob
44103285Sikob#include "fetch.h"
45103285Sikob#include "common.h"
46103285Sikob
47103285Sikob
48103285Sikob/*** Local data **************************************************************/
49113584Ssimokawa
50103285Sikob/*
51103285Sikob * Error messages for resolver errors
52103285Sikob */
53103285Sikobstatic struct fetcherr _netdb_errlist[] = {
54103285Sikob    { EAI_NODATA,	FETCH_RESOLV,	"Host not found" },
55127468Ssimokawa    { EAI_AGAIN,	FETCH_TEMP,	"Transient resolver failure" },
56127468Ssimokawa    { EAI_FAIL,		FETCH_RESOLV,	"Non-recoverable resolver failure" },
57127468Ssimokawa    { EAI_NONAME,	FETCH_RESOLV,	"No address record" },
58127468Ssimokawa    { -1,		FETCH_UNKNOWN,	"Unknown resolver error" }
59127468Ssimokawa};
60127468Ssimokawa
61103285Sikob
62103285Sikob/*** Error-reporting functions ***********************************************/
63103285Sikob
64103285Sikob/*
65103285Sikob * Map error code to string
66127468Ssimokawa */
67103285Sikobstatic struct fetcherr *
68122161Ssimokawa_fetch_finderr(struct fetcherr *p, int e)
69111942Ssimokawa{
70103285Sikob    while (p->num != -1 && p->num != e)
71103285Sikob	p++;
72124169Ssimokawa    return p;
73124169Ssimokawa}
74124169Ssimokawa
75103285Sikob/*
76124169Ssimokawa * Set error code
77124169Ssimokawa */
78124169Ssimokawavoid
79103285Sikob_fetch_seterr(struct fetcherr *p, int e)
80103285Sikob{
81103285Sikob    p = _fetch_finderr(p, e);
82116139Ssimokawa    fetchLastErrCode = p->cat;
83122603Ssimokawa    snprintf(fetchLastErrString, MAXERRSTRING, "%s", p->string);
84103285Sikob}
85108281Ssimokawa
86103285Sikob/*
87103285Sikob * Set error code according to errno
88103285Sikob */
89122603Ssimokawavoid
90103285Sikob_fetch_syserr(void)
91103285Sikob{
92116139Ssimokawa    int e;
93122603Ssimokawa    e = errno;
94122603Ssimokawa
95122603Ssimokawa    switch (errno) {
96103285Sikob    case 0:
97122603Ssimokawa	fetchLastErrCode = FETCH_OK;
98122603Ssimokawa	break;
99122603Ssimokawa    case EPERM:
100122603Ssimokawa    case EACCES:
101103285Sikob    case EROFS:
102103285Sikob    case EAUTH:
103103285Sikob    case ENEEDAUTH:
104103285Sikob	fetchLastErrCode = FETCH_AUTH;
105103285Sikob	break;
106103285Sikob    case ENOENT:
107103285Sikob    case EISDIR: /* XXX */
108103285Sikob	fetchLastErrCode = FETCH_UNAVAIL;
109103285Sikob	break;
110103285Sikob    case ENOMEM:
111103285Sikob	fetchLastErrCode = FETCH_MEMORY;
112103285Sikob	break;
113103285Sikob    case EBUSY:
114103285Sikob    case EAGAIN:
115103285Sikob	fetchLastErrCode = FETCH_TEMP;
116103285Sikob	break;
117103285Sikob    case EEXIST:
118103285Sikob	fetchLastErrCode = FETCH_EXISTS;
119103285Sikob	break;
120103285Sikob    case ENOSPC:
121103285Sikob	fetchLastErrCode = FETCH_FULL;
122103285Sikob	break;
123103285Sikob    case EADDRINUSE:
124103285Sikob    case EADDRNOTAVAIL:
125103285Sikob    case ENETDOWN:
126103285Sikob    case ENETUNREACH:
127103285Sikob    case ENETRESET:
128103285Sikob    case EHOSTUNREACH:
129103285Sikob	fetchLastErrCode = FETCH_NETWORK;
130103285Sikob	break;
131103285Sikob    case ECONNABORTED:
132103285Sikob    case ECONNRESET:
133103285Sikob	fetchLastErrCode = FETCH_ABORT;
134103285Sikob	break;
135103285Sikob    case ETIMEDOUT:
136103285Sikob	fetchLastErrCode = FETCH_TIMEOUT;
137103285Sikob	break;
138103285Sikob    case ECONNREFUSED:
139121953Ssimokawa    case EHOSTDOWN:
140103285Sikob	fetchLastErrCode = FETCH_DOWN;
141103285Sikob	break;
142103285Sikob    default:
143103285Sikob	fetchLastErrCode = FETCH_UNKNOWN;
144103285Sikob    }
145103285Sikob    snprintf(fetchLastErrString, MAXERRSTRING, "%s", strerror(e));
146103285Sikob}
147103285Sikob
148103285Sikob
149103285Sikob/*
150103285Sikob * Emit status message
151103285Sikob */
152108281Ssimokawavoid
153103285Sikob_fetch_info(char *fmt, ...)
154103285Sikob{
155103285Sikob    va_list ap;
156103285Sikob
157103285Sikob    va_start(ap, fmt);
158103285Sikob    vfprintf(stderr, fmt, ap);
159103285Sikob    va_end(ap);
160103285Sikob    fputc('\n', stderr);
161103285Sikob}
162103285Sikob
163109814Ssimokawa
164103285Sikob/*** Network-related utility functions ***************************************/
165103285Sikob
166103285Sikob/*
167103285Sikob * Establish a TCP connection to the specified port on the specified host.
168103285Sikob */
169103285Sikobint
170103285Sikob_fetch_connect(char *host, int port, int af, int verbose)
171103285Sikob{
172103285Sikob    char pbuf[10];
173103285Sikob    struct addrinfo hints, *res, *res0;
174124251Ssimokawa    int sd, err;
175124251Ssimokawa
176124251Ssimokawa    DEBUG(fprintf(stderr, "\033[1m---> %s:%d\033[m\n", host, port));
177103285Sikob
178103285Sikob    if (verbose)
179103285Sikob	_fetch_info("looking up %s", host);
180103285Sikob
181103285Sikob    /* look up host name and set up socket address structure */
182103285Sikob    snprintf(pbuf, sizeof(pbuf), "%d", port);
183103285Sikob    memset(&hints, 0, sizeof(hints));
184103285Sikob    hints.ai_family = af;
185103285Sikob    hints.ai_socktype = SOCK_STREAM;
186103285Sikob    hints.ai_protocol = 0;
187103285Sikob    if ((err = getaddrinfo(host, pbuf, &hints, &res0)) != 0) {
188103285Sikob	_netdb_seterr(err);
189109814Ssimokawa	return -1;
190109814Ssimokawa    }
191109814Ssimokawa
192109814Ssimokawa    if (verbose)
193109814Ssimokawa	_fetch_info("connecting to %s:%d", host, port);
194109814Ssimokawa
195109814Ssimokawa    /* try to connect */
196109814Ssimokawa    sd = -1;
197107653Ssimokawa    for (res = res0; res; res = res->ai_next) {
198107653Ssimokawa	if ((sd = socket(res->ai_family, res->ai_socktype,
199103285Sikob			 res->ai_protocol)) < 0)
200103285Sikob	    continue;
201103285Sikob	if (connect(sd, res->ai_addr, res->ai_addrlen) >= 0)
202103285Sikob	    break;
203103285Sikob	close(sd);
204103285Sikob	sd = -1;
205127468Ssimokawa    }
206121953Ssimokawa    freeaddrinfo(res0);
207122212Ssimokawa    if (sd < 0) {
208122212Ssimokawa	_fetch_syserr();
209122212Ssimokawa	return -1;
210122212Ssimokawa    }
211103285Sikob
212132430Ssimokawa    return sd;
213132430Ssimokawa}
214132430Ssimokawa
215103285Sikob
216103285Sikob/*
217103285Sikob * Read a line of text from a socket w/ timeout
218103285Sikob */
219111942Ssimokawa#define MIN_BUF_SIZE 1024
220103285Sikob
221103285Sikobint
222127468Ssimokawa_fetch_getln(int fd, char **buf, size_t *size, size_t *len)
223127468Ssimokawa{
224127468Ssimokawa    struct timeval now, timeout, wait;
225106937Ssam    fd_set readfds;
226108712Ssimokawa    int r;
227103285Sikob    char c;
228103285Sikob
229103285Sikob    if (*buf == NULL) {
230103285Sikob	if ((*buf = malloc(MIN_BUF_SIZE)) == NULL) {
231127468Ssimokawa	    errno = ENOMEM;
232106937Ssam	    return -1;
233129552Syar	}
234108712Ssimokawa	*size = MIN_BUF_SIZE;
235103285Sikob    }
236103285Sikob
237122161Ssimokawa    **buf = '\0';
238103285Sikob    *len = 0;
239103285Sikob
240103285Sikob    if (fetchTimeout) {
241103285Sikob	gettimeofday(&timeout, NULL);
242103285Sikob	timeout.tv_sec += fetchTimeout;
243103285Sikob	FD_ZERO(&readfds);
244103285Sikob    }
245103285Sikob
246103285Sikob    do {
247111942Ssimokawa	if (fetchTimeout) {
248111942Ssimokawa	    FD_SET(fd, &readfds);
249103285Sikob	    gettimeofday(&now, NULL);
250103285Sikob	    wait.tv_sec = timeout.tv_sec - now.tv_sec;
251103285Sikob	    wait.tv_usec = timeout.tv_usec - now.tv_usec;
252103285Sikob	    if (wait.tv_usec < 0) {
253103285Sikob		wait.tv_usec += 1000000;
254103285Sikob		wait.tv_sec--;
255103285Sikob	    }
256103285Sikob	    if (wait.tv_sec < 0) {
257103285Sikob		errno = ETIMEDOUT;
258103285Sikob		return -1;
259103285Sikob	    }
260113584Ssimokawa	    r = select(fd+1, &readfds, NULL, NULL, &wait);
261113584Ssimokawa	    if (r == -1) {
262111942Ssimokawa		if (errno == EINTR)
263111942Ssimokawa		    continue;
264111942Ssimokawa		/* EBADF or EINVAL: shouldn't happen */
265111942Ssimokawa		return -1;
266111942Ssimokawa	    }
267111942Ssimokawa	    if (!FD_ISSET(fd, &readfds))
268111942Ssimokawa		continue;
269111942Ssimokawa	}
270111942Ssimokawa	r = read(fd, &c, 1);
271111942Ssimokawa	if (r == 0)
272111942Ssimokawa	    break;
273111942Ssimokawa	if (r == -1) {
274111942Ssimokawa	    if (errno == EINTR)
275111942Ssimokawa		continue;
276103285Sikob	    /* any other error is bad news */
277103285Sikob	    return -1;
278103285Sikob	}
279103285Sikob	(*buf)[*len] = c;
280103285Sikob	*len += 1;
281103285Sikob	if (*len == *size) {
282103285Sikob	    char *tmp;
283103285Sikob
284103285Sikob	    if ((tmp = realloc(*buf, *size * 2 + 1)) == NULL) {
285103285Sikob		errno = ENOMEM;
286103285Sikob		return -1;
287103285Sikob	    }
288103285Sikob	    *buf = tmp;
289103285Sikob	    *size = *size * 2 + 1;
290103285Sikob	}
291103285Sikob    } while (c != '\n');
292127468Ssimokawa
293127468Ssimokawa    DEBUG(fprintf(stderr, "\033[1m<<< %.*s\033[m", (int)*len, *buf));
294127468Ssimokawa    return 0;
295106937Ssam}
296108712Ssimokawa
297103285Sikob
298103285Sikob/*** Directory-related utility functions *************************************/
299103285Sikob
300103285Sikobint
301103285Sikob_fetch_add_entry(struct url_ent **p, int *size, int *len,
302103285Sikob		 char *name, struct url_stat *stat)
303103285Sikob{
304103285Sikob    struct url_ent *tmp;
305103285Sikob
306103285Sikob    if (*p == NULL) {
307103285Sikob#define INITIAL_SIZE 8
308103285Sikob	if ((*p = malloc(INITIAL_SIZE * sizeof **p)) == NULL) {
309111942Ssimokawa	    errno = ENOMEM;
310113584Ssimokawa	    _fetch_syserr();
311103285Sikob	    return -1;
312103285Sikob	}
313122161Ssimokawa	*size = INITIAL_SIZE;
314103285Sikob	*len = 0;
315103285Sikob#undef INITIAL_SIZE
316103285Sikob    }
317103285Sikob
318103285Sikob    if (*len >= *size - 1) {
319103285Sikob	tmp = realloc(*p, *size * 2 * sizeof **p);
320103285Sikob	if (tmp == NULL) {
321103285Sikob	    errno = ENOMEM;
322103285Sikob	    _fetch_syserr();
323103285Sikob	    return -1;
324118312Ssimokawa	}
325103285Sikob	*size *= 2;
326118312Ssimokawa	*p = tmp;
327118312Ssimokawa    }
328118312Ssimokawa
329103285Sikob    tmp = *p + *len;
330103285Sikob    snprintf(tmp->name, MAXPATHLEN, "%s", name);
331103285Sikob    bcopy(stat, &tmp->stat, sizeof *stat);
332103285Sikob
333113584Ssimokawa    (*len)++;
334113584Ssimokawa    (++tmp)->name[0] = 0;
335112400Ssimokawa
336103285Sikob    return 0;
337103285Sikob}
338103285Sikob