common.c revision 41862
140939Sdes/*-
240939Sdes * Copyright (c) 1998 Dag-Erling Co�dan Sm�rgrav
340939Sdes * All rights reserved.
440939Sdes *
540939Sdes * Redistribution and use in source and binary forms, with or without
640939Sdes * modification, are permitted provided that the following conditions
740939Sdes * are met:
840939Sdes * 1. Redistributions of source code must retain the above copyright
940939Sdes *    notice, this list of conditions and the following disclaimer
1040939Sdes *    in this position and unchanged.
1140939Sdes * 2. Redistributions in binary form must reproduce the above copyright
1240939Sdes *    notice, this list of conditions and the following disclaimer in the
1340939Sdes *    documentation and/or other materials provided with the distribution.
1440939Sdes * 3. The name of the author may not be used to endorse or promote products
1540939Sdes *    derived from this software without specific prior written permission
1640939Sdes *
1740939Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1840939Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1940939Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2040939Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2140939Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2240939Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2340939Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2440939Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2540939Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2640939Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2740939Sdes *
2841862Sdes *	$Id: common.c,v 1.2 1998/11/06 22:14:08 des Exp $
2940939Sdes */
3040939Sdes
3141862Sdes#include <sys/param.h>
3240939Sdes#include <sys/socket.h>
3340939Sdes#include <netinet/in.h>
3440939Sdes
3540975Sdes#include <com_err.h>
3640939Sdes#include <errno.h>
3740939Sdes#include <netdb.h>
3841862Sdes#include <stdlib.h>
3941862Sdes#include <stdio.h>
4040939Sdes#include <string.h>
4140939Sdes#include <unistd.h>
4240939Sdes
4340939Sdes#include "fetch.h"
4440939Sdes#include "common.h"
4540939Sdes
4640975Sdes
4740939Sdes/*** Local data **************************************************************/
4840939Sdes
4940939Sdes/*
5040939Sdes * Error messages for resolver errors
5140939Sdes */
5240939Sdesstatic struct fetcherr _netdb_errlist[] = {
5340975Sdes    { HOST_NOT_FOUND,	FETCH_RESOLV,	"Host not found" },
5441862Sdes    { TRY_AGAIN,	FETCH_TEMP,	"Transient resolver failure" },
5540975Sdes    { NO_RECOVERY,	FETCH_RESOLV,	"Non-recoverable resolver failure" },
5640975Sdes    { NO_DATA,		FETCH_RESOLV,	"No address record" },
5740975Sdes    { -1,		FETCH_UNKNOWN,	"Unknown resolver error" }
5840939Sdes};
5940939Sdes
6040975Sdesstatic int com_err_initialized;
6140939Sdes
6240939Sdes/*** Error-reporting functions ***********************************************/
6340939Sdes
6440939Sdes/*
6540975Sdes * Initialize the common error library
6640975Sdes */
6740975Sdesstatic void
6840975Sdes_fetch_init_com_err(void)
6940975Sdes{
7040975Sdes    initialize_ftch_error_table();
7140975Sdes    com_err_initialized = 1;
7240975Sdes}
7340975Sdes
7440975Sdes/*
7540939Sdes * Map error code to string
7640939Sdes */
7740975Sdesstatic int
7840975Sdes_fetch_finderr(struct fetcherr *p, int e)
7940939Sdes{
8040975Sdes    int i;
8140975Sdes    for (i = 0; p[i].num != -1; i++)
8240975Sdes	if (p[i].num == e)
8340975Sdes	    break;
8440975Sdes    return i;
8540939Sdes}
8640939Sdes
8740939Sdes/*
8840939Sdes * Set error code
8940939Sdes */
9040939Sdesvoid
9140939Sdes_fetch_seterr(struct fetcherr *p, int e)
9240939Sdes{
9340975Sdes    int n;
9440975Sdes
9540975Sdes    if (!com_err_initialized)
9640975Sdes	_fetch_init_com_err();
9740975Sdes
9840975Sdes    n = _fetch_finderr(p, e);
9941862Sdes    fetchLastErrCode = p[n].cat;
10041862Sdes    com_err("libfetch", fetchLastErrCode, "(%03d %s)", e, p[n].string);
10140939Sdes}
10240939Sdes
10340939Sdes/*
10440939Sdes * Set error code according to errno
10540939Sdes */
10640939Sdesvoid
10740939Sdes_fetch_syserr(void)
10840939Sdes{
10941862Sdes    int e;
11041862Sdes    e = errno;
11140975Sdes
11240975Sdes    if (!com_err_initialized)
11340975Sdes	_fetch_init_com_err();
11440975Sdes
11540975Sdes    switch (errno) {
11640975Sdes    case 0:
11741862Sdes	fetchLastErrCode = FETCH_OK;
11840975Sdes	break;
11940975Sdes    case EPERM:
12040975Sdes    case EACCES:
12140975Sdes    case EROFS:
12240975Sdes    case EAUTH:
12340975Sdes    case ENEEDAUTH:
12441862Sdes	fetchLastErrCode = FETCH_AUTH;
12540975Sdes	break;
12640975Sdes    case ENOENT:
12740975Sdes    case EISDIR: /* XXX */
12841862Sdes	fetchLastErrCode = FETCH_UNAVAIL;
12940975Sdes	break;
13040975Sdes    case ENOMEM:
13141862Sdes	fetchLastErrCode = FETCH_MEMORY;
13240975Sdes	break;
13340975Sdes    case EBUSY:
13440975Sdes    case EAGAIN:
13541862Sdes	fetchLastErrCode = FETCH_TEMP;
13640975Sdes	break;
13740975Sdes    case EEXIST:
13841862Sdes	fetchLastErrCode = FETCH_EXISTS;
13940975Sdes	break;
14040975Sdes    case ENOSPC:
14141862Sdes	fetchLastErrCode = FETCH_FULL;
14240975Sdes	break;
14340975Sdes    case EADDRINUSE:
14440975Sdes    case EADDRNOTAVAIL:
14540975Sdes    case ENETDOWN:
14640975Sdes    case ENETUNREACH:
14740975Sdes    case ENETRESET:
14840975Sdes    case EHOSTUNREACH:
14941862Sdes	fetchLastErrCode = FETCH_NETWORK;
15040975Sdes	break;
15140975Sdes    case ECONNABORTED:
15240975Sdes    case ECONNRESET:
15341862Sdes	fetchLastErrCode = FETCH_ABORT;
15440975Sdes	break;
15540975Sdes    case ETIMEDOUT:
15641862Sdes	fetchLastErrCode = FETCH_TIMEOUT;
15740975Sdes	break;
15840975Sdes    case ECONNREFUSED:
15940975Sdes    case EHOSTDOWN:
16041862Sdes	fetchLastErrCode = FETCH_DOWN;
16140975Sdes	break;
16240975Sdes    default:
16341862Sdes	fetchLastErrCode = FETCH_UNKNOWN;
16440975Sdes    }
16541862Sdes    com_err("libfetch", fetchLastErrCode, "(%03d %s)", e, strerror(e));
16640939Sdes}
16740939Sdes
16840939Sdes
16941862Sdes/*
17041862Sdes * Emit status message
17141862Sdes */
17241862Sdesint
17341862Sdes_fetch_info(char *fmt, ...)
17441862Sdes{
17541862Sdes    va_list ap;
17641862Sdes    char *s;
17741862Sdes
17841862Sdes    if (!com_err_initialized)
17941862Sdes	_fetch_init_com_err();
18041862Sdes
18141862Sdes    va_start(ap, fmt);
18241862Sdes    vasprintf(&s, fmt, ap);
18341862Sdes    va_end(ap);
18441862Sdes
18541862Sdes    if (s == NULL) {
18641862Sdes	com_err("libfetch", FETCH_MEMORY, "");
18741862Sdes	return -1;
18841862Sdes    } else {
18941862Sdes	com_err("libfetch", FETCH_VERBOSE, "%s", s);
19041862Sdes	free(s);
19141862Sdes	return 0;
19241862Sdes    }
19341862Sdes}
19441862Sdes
19541862Sdes
19640939Sdes/*** Network-related utility functions ***************************************/
19740939Sdes
19840939Sdes/*
19940939Sdes * Establish a TCP connection to the specified port on the specified host.
20040939Sdes */
20140939Sdesint
20241862SdesfetchConnect(char *host, int port, int verbose)
20340939Sdes{
20440939Sdes    struct sockaddr_in sin;
20540939Sdes    struct hostent *he;
20640939Sdes    int sd;
20740939Sdes
20840939Sdes#ifndef NDEBUG
20940939Sdes    fprintf(stderr, "\033[1m---> %s:%d\033[m\n", host, port);
21040939Sdes#endif
21141862Sdes
21241862Sdes    if (verbose)
21341862Sdes	_fetch_info("looking up %s", host);
21440939Sdes
21540939Sdes    /* look up host name */
21640939Sdes    if ((he = gethostbyname(host)) == NULL) {
21740939Sdes	_netdb_seterr(h_errno);
21840939Sdes	return -1;
21940939Sdes    }
22040939Sdes
22141862Sdes    if (verbose)
22241862Sdes	_fetch_info("connecting to %s:%d", host, port);
22341862Sdes
22440939Sdes    /* set up socket address structure */
22540939Sdes    bzero(&sin, sizeof(sin));
22640939Sdes    bcopy(he->h_addr, (char *)&sin.sin_addr, he->h_length);
22740939Sdes    sin.sin_family = he->h_addrtype;
22840939Sdes    sin.sin_port = htons(port);
22940939Sdes
23040939Sdes    /* try to connect */
23140939Sdes    if ((sd = socket(sin.sin_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
23240939Sdes	_fetch_syserr();
23340939Sdes	return -1;
23440939Sdes    }
23540939Sdes    if (connect(sd, (struct sockaddr *)&sin, sizeof sin) == -1) {
23640939Sdes	_fetch_syserr();
23740939Sdes	close(sd);
23840939Sdes	return -1;
23940939Sdes    }
24040939Sdes
24140939Sdes    return sd;
24240939Sdes}
243