common.c revision 41923
1/*-
2 * Copyright (c) 1998 Dag-Erling Co�dan Sm�rgrav
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer
10 *    in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 *    derived from this software without specific prior written permission
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 *	$Id: common.c,v 1.3 1998/12/16 10:24:52 des Exp $
29 */
30
31#include <sys/param.h>
32#include <sys/socket.h>
33#include <netinet/in.h>
34
35#include <com_err.h>
36#include <errno.h>
37#include <netdb.h>
38#include <stdlib.h>
39#include <stdio.h>
40#include <string.h>
41#include <unistd.h>
42
43#include "fetch.h"
44#include "common.h"
45
46
47/*** Local data **************************************************************/
48
49/*
50 * Error messages for resolver errors
51 */
52static struct fetcherr _netdb_errlist[] = {
53    { HOST_NOT_FOUND,	FETCH_RESOLV,	"Host not found" },
54    { TRY_AGAIN,	FETCH_TEMP,	"Transient resolver failure" },
55    { NO_RECOVERY,	FETCH_RESOLV,	"Non-recoverable resolver failure" },
56    { NO_DATA,		FETCH_RESOLV,	"No address record" },
57    { -1,		FETCH_UNKNOWN,	"Unknown resolver error" }
58};
59
60static int com_err_initialized;
61
62/*** Error-reporting functions ***********************************************/
63
64/*
65 * Initialize the common error library
66 */
67static void
68_fetch_init_com_err(void)
69{
70    initialize_ftch_error_table();
71    com_err_initialized = 1;
72}
73
74/*
75 * Map error code to string
76 */
77static int
78_fetch_finderr(struct fetcherr *p, int e)
79{
80    int i;
81    for (i = 0; p[i].num != -1; i++)
82	if (p[i].num == e)
83	    break;
84    return i;
85}
86
87/*
88 * Set error code
89 */
90void
91_fetch_seterr(struct fetcherr *p, int e)
92{
93    int n;
94
95    if (!com_err_initialized)
96	_fetch_init_com_err();
97
98    n = _fetch_finderr(p, e);
99    fetchLastErrCode = p[n].cat;
100    com_err("libfetch", fetchLastErrCode, "(%03d %s)", e, p[n].string);
101}
102
103/*
104 * Set error code according to errno
105 */
106void
107_fetch_syserr(void)
108{
109    int e;
110    e = errno;
111
112    if (!com_err_initialized)
113	_fetch_init_com_err();
114
115    switch (errno) {
116    case 0:
117	fetchLastErrCode = FETCH_OK;
118	break;
119    case EPERM:
120    case EACCES:
121    case EROFS:
122    case EAUTH:
123    case ENEEDAUTH:
124	fetchLastErrCode = FETCH_AUTH;
125	break;
126    case ENOENT:
127    case EISDIR: /* XXX */
128	fetchLastErrCode = FETCH_UNAVAIL;
129	break;
130    case ENOMEM:
131	fetchLastErrCode = FETCH_MEMORY;
132	break;
133    case EBUSY:
134    case EAGAIN:
135	fetchLastErrCode = FETCH_TEMP;
136	break;
137    case EEXIST:
138	fetchLastErrCode = FETCH_EXISTS;
139	break;
140    case ENOSPC:
141	fetchLastErrCode = FETCH_FULL;
142	break;
143    case EADDRINUSE:
144    case EADDRNOTAVAIL:
145    case ENETDOWN:
146    case ENETUNREACH:
147    case ENETRESET:
148    case EHOSTUNREACH:
149	fetchLastErrCode = FETCH_NETWORK;
150	break;
151    case ECONNABORTED:
152    case ECONNRESET:
153	fetchLastErrCode = FETCH_ABORT;
154	break;
155    case ETIMEDOUT:
156	fetchLastErrCode = FETCH_TIMEOUT;
157	break;
158    case ECONNREFUSED:
159    case EHOSTDOWN:
160	fetchLastErrCode = FETCH_DOWN;
161	break;
162    default:
163	fetchLastErrCode = FETCH_UNKNOWN;
164    }
165    com_err("libfetch", fetchLastErrCode, "(%03d %s)", e, strerror(e));
166}
167
168
169/*
170 * Emit status message
171 */
172int
173_fetch_info(char *fmt, ...)
174{
175    va_list ap;
176    char *s;
177
178    if (!com_err_initialized)
179	_fetch_init_com_err();
180
181    va_start(ap, fmt);
182    vasprintf(&s, fmt, ap);
183    va_end(ap);
184
185    if (s == NULL) {
186	com_err("libfetch", FETCH_MEMORY, "");
187	return -1;
188    } else {
189	com_err("libfetch", FETCH_VERBOSE, "%s", s);
190	free(s);
191	return 0;
192    }
193}
194
195
196/*** Network-related utility functions ***************************************/
197
198/*
199 * Establish a TCP connection to the specified port on the specified host.
200 */
201int
202_fetch_connect(char *host, int port, int verbose)
203{
204    struct sockaddr_in sin;
205    struct hostent *he;
206    int sd;
207
208#ifndef NDEBUG
209    fprintf(stderr, "\033[1m---> %s:%d\033[m\n", host, port);
210#endif
211
212    if (verbose)
213	_fetch_info("looking up %s", host);
214
215    /* look up host name */
216    if ((he = gethostbyname(host)) == NULL) {
217	_netdb_seterr(h_errno);
218	return -1;
219    }
220
221    if (verbose)
222	_fetch_info("connecting to %s:%d", host, port);
223
224    /* set up socket address structure */
225    bzero(&sin, sizeof(sin));
226    bcopy(he->h_addr, (char *)&sin.sin_addr, he->h_length);
227    sin.sin_family = he->h_addrtype;
228    sin.sin_port = htons(port);
229
230    /* try to connect */
231    if ((sd = socket(sin.sin_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
232	_fetch_syserr();
233	return -1;
234    }
235    if (connect(sd, (struct sockaddr *)&sin, sizeof sin) == -1) {
236	_fetch_syserr();
237	close(sd);
238	return -1;
239    }
240
241    return sd;
242}
243