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