From 934b6582b4518630a050c8b84853b8e78ed87905 Mon Sep 17 00:00:00 2001 From: Arch Librarian Date: Mon, 20 Sep 2004 16:53:50 +0000 Subject: Changed to using rfc2553 name resolution for http Author: jgg Date: 1999-05-25 05:56:24 GMT Changed to using rfc2553 name resolution for http --- methods/ftp.cc | 6 ++- methods/http.cc | 58 +++++++++++++-------- methods/makefile | 2 +- methods/rfc2553emu.cc | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++ methods/rfc2553emu.h | 85 ++++++++++++++++++++++++++++++ 5 files changed, 266 insertions(+), 24 deletions(-) create mode 100644 methods/rfc2553emu.cc create mode 100644 methods/rfc2553emu.h diff --git a/methods/ftp.cc b/methods/ftp.cc index a93777488..b567875e1 100644 --- a/methods/ftp.cc +++ b/methods/ftp.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: ftp.cc,v 1.9 1999/05/23 23:30:09 jgg Exp $ +// $Id: ftp.cc,v 1.10 1999/05/25 05:56:24 jgg Exp $ /* ###################################################################### HTTP Aquire Method - This is the FTP aquire method for APT. @@ -9,7 +9,9 @@ at all. Commands are sent syncronously with the FTP server (as the rfc recommends, but it is not really necessary..) and no tricks are done to speed things along. - + + RFC 2428 describes the IPv6 FTP behavior + ##################################################################### */ /*}}}*/ // Include Files /*{{{*/ diff --git a/methods/http.cc b/methods/http.cc index 4bd7975a4..0c0acf60f 100644 --- a/methods/http.cc +++ b/methods/http.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: http.cc,v 1.30 1999/04/04 02:02:04 jgg Exp $ +// $Id: http.cc,v 1.31 1999/05/25 05:56:24 jgg Exp $ /* ###################################################################### HTTP Aquire Method - This is the HTTP aquire method for APT. @@ -41,12 +41,14 @@ #include // Internet stuff -#include +/*#include #include #include -#include +#include */ +#include "rfc2553emu.h" #include "http.h" + /*}}}*/ string HttpMethod::FailFile; @@ -258,7 +260,8 @@ ServerState::ServerState(URI Srv,HttpMethod *Owner) : Owner(Owner), // --------------------------------------------------------------------- /* This opens a connection to the server. */ string LastHost; -in_addr LastHostA; +int LastPort = 0; +struct addrinfo *LastHostAddr = 0; bool ServerState::Open() { // Use the already open connection if possible. @@ -288,7 +291,7 @@ bool ServerState::Open() Proxy = getenv("http_proxy"); // Determine what host and port to use based on the proxy settings - int Port = 80; + int Port = 0; string Host; if (Proxy.empty() == true) { @@ -306,33 +309,46 @@ bool ServerState::Open() /* We used a cached address record.. Yes this is against the spec but the way we have setup our rotating dns suggests that this is more sensible */ - if (LastHost != Host) + if (LastHost != Host || LastPort != Port) { Owner->Status("Connecting to %s",Host.c_str()); // Lookup the host - hostent *Addr = gethostbyname(Host.c_str()); - if (Addr == 0 || Addr->h_addr_list[0] == 0) + char S[30] = "http"; + if (Port != 0) + snprintf(S,sizeof(S),"%u",Port); + + // Free the old address structure + if (LastHostAddr != 0) + { + freeaddrinfo(LastHostAddr); + LastHostAddr = 0; + } + + // We only understand SOCK_STREAM sockets. + struct addrinfo Hints; + memset(&Hints,0,sizeof(Hints)); + Hints.ai_socktype = SOCK_STREAM; + + // Resolve both the host and service simultaneously + if (getaddrinfo(Host.c_str(),S,&Hints,&LastHostAddr) != 0 || + LastHostAddr == 0) return _error->Error("Could not resolve '%s'",Host.c_str()); + LastHost = Host; - LastHostA = *(in_addr *)(Addr->h_addr_list[0]); + LastPort = Port; } - - Owner->Status("Connecting to %s (%s)",Host.c_str(),inet_ntoa(LastHostA)); - + + // Connect to the server // Get a socket - if ((ServerFd = socket(AF_INET,SOCK_STREAM,0)) < 0) +// Owner->Status("Connecting to %s (%s)",Host.c_str(),inet_ntoa(LastHostA)); + if ((ServerFd = socket(LastHostAddr->ai_family,LastHostAddr->ai_socktype, + LastHostAddr->ai_protocol)) < 0) return _error->Errno("socket","Could not create a socket"); - - // Connect to the server - struct sockaddr_in server; - server.sin_family = AF_INET; - server.sin_port = htons(Port); - server.sin_addr = LastHostA; SetNonBlock(ServerFd,true); - if (connect(ServerFd,(sockaddr *)&server,sizeof(server)) < 0 && + if (connect(ServerFd,LastHostAddr->ai_addr,LastHostAddr->ai_addrlen) < 0 && errno != EINPROGRESS) - return _error->Errno("socket","Could not create a socket"); + return _error->Errno("connect","Connect initiate the connection"); /* This implements a timeout for connect by opening the connection nonblocking */ diff --git a/methods/makefile b/methods/makefile index dc6b88780..2cfc15cae 100644 --- a/methods/makefile +++ b/methods/makefile @@ -38,7 +38,7 @@ include $(PROGRAM_H) PROGRAM=http SLIBS = -lapt-pkg LIB_MAKES = apt-pkg/makefile -SOURCE = http.cc +SOURCE = http.cc rfc2553emu.cc include $(PROGRAM_H) # The ftp method diff --git a/methods/rfc2553emu.cc b/methods/rfc2553emu.cc new file mode 100644 index 000000000..66fe781fb --- /dev/null +++ b/methods/rfc2553emu.cc @@ -0,0 +1,139 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: rfc2553emu.cc,v 1.1 1999/05/25 05:56:24 jgg Exp $ +/* ###################################################################### + + RFC 2553 Emulation - Provides emulation for RFC 2553 getaddrinfo, + freeaddrinfo and getnameinfo + + Originally written by Jason Gunthorpe and placed into + the Public Domain, do with it what you will. + + ##################################################################### */ + /*}}}*/ +#include "rfc2553emu.h" +#include +#include +#include + +#ifndef HAVE_GETADDRINFO +int getaddrinfo(const char *nodename, const char *servname, + const struct addrinfo *hints, + struct addrinfo **res) +{ + struct addrinfo **Result; + hostent *Addr; + unsigned int Port; + int Proto; + const char *End; + char **CurAddr; + + Addr = gethostbyname(nodename); + if (Addr == 0) + { + if (h_errno == TRY_AGAIN) + return EAI_AGAIN; + if (h_errno == NO_RECOVERY) + return EAI_FAIL; + return EAI_NONAME; + } + + // No A records + if (Addr->h_addr_list[0] == 0) + return EAI_NONAME; + + // Try to convert the service as a number + Port = htons(strtol(servname,(char **)&End,0)); + Proto = SOCK_STREAM; + + if (hints != 0 && hints->ai_socktype != 0) + Proto = hints->ai_socktype; + + // Not a number, must be a name. + if (End != servname + strlen(End)) + { + struct servent *Srv = 0; + + // Do a lookup in the service database + if (hints == 0 || hints->ai_socktype == SOCK_STREAM) + Srv = getservbyname(servname,"tcp"); + if (hints != 0 && hints->ai_socktype == SOCK_DGRAM) + Srv = getservbyname(servname,"udp"); + if (Srv == 0) + return EAI_NONAME; + + // Get the right protocol + Port = Srv->s_port; + if (strcmp(Srv->s_proto,"tcp") == 0) + Proto = SOCK_STREAM; + else + { + if (strcmp(Srv->s_proto,"udp") == 0) + Proto = SOCK_DGRAM; + else + return EAI_NONAME; + } + + if (hints != 0 && hints->ai_socktype != Proto && + hints->ai_socktype != 0) + return EAI_SERVICE; + } + + // Start constructing the linked list + *res = 0; + for (CurAddr = Addr->h_addr_list; *CurAddr != 0; CurAddr++) + { + // New result structure + *Result = (struct addrinfo *)calloc(sizeof(**Result),1); + if (*Result == 0) + { + freeaddrinfo(*res); + return EAI_MEMORY; + } + if (*res == 0) + *res = *Result; + + (*Result)->ai_family = AF_INET; + (*Result)->ai_socktype = Proto; + + // If we have the IPPROTO defines we can set the protocol field + #ifdef IPPROTO_TCP + if (Proto == SOCK_STREAM) + (*Result)->ai_protocol = IPPROTO_TCP; + if (Proto == SOCK_DGRAM) + (*Result)->ai_protocol = IPPROTO_UDP; + #endif + + // Allocate space for the address + (*Result)->ai_addrlen = sizeof(struct sockaddr_in); + (*Result)->ai_addr = (struct sockaddr *)calloc(sizeof(sockaddr_in),1); + if ((*Result)->ai_addr == 0) + { + freeaddrinfo(*res); + return EAI_MEMORY; + } + + // Set the address + ((struct sockaddr_in *)(*Result)->ai_addr)->sin_family = AF_INET; + ((struct sockaddr_in *)(*Result)->ai_addr)->sin_port = Port; + ((struct sockaddr_in *)(*Result)->ai_addr)->sin_addr = *(in_addr *)(*CurAddr); + + Result = &(*Result)->ai_next; + } + + return 0; +} + +void freeaddrinfo(struct addrinfo *ai) +{ + struct addrinfo *Tmp; + while (ai != 0) + { + free(ai->ai_addr); + Tmp = ai; + ai = ai->ai_next; + free(ai); + } +} + +#endif // HAVE_GETADDRINFO diff --git a/methods/rfc2553emu.h b/methods/rfc2553emu.h new file mode 100644 index 000000000..e24e7a3c1 --- /dev/null +++ b/methods/rfc2553emu.h @@ -0,0 +1,85 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: rfc2553emu.h,v 1.1 1999/05/25 05:56:24 jgg Exp $ +/* ###################################################################### + + RFC 2553 Emulation - Provides emulation for RFC 2553 getaddrinfo, + freeaddrinfo and getnameinfo + + These functions are necessary to write portable protocol independent + networking. They transparently support IPv4, IPv6 and probably many + other protocols too. This implementation is needed when the host does + not support these standards. It implements a simple wrapper that + basically supports only IPv4. + + Perfect emulation is not provided, but it is passable.. + + Originally written by Jason Gunthorpe and placed into + the Public Domain, do with it what you will. + + ##################################################################### */ + /*}}}*/ +#ifndef RFC2553EMU_H +#define RFC2553EMU_H + +#include +#include +#include + +// Autosense getaddrinfo +#if defined(AI_PASSIVE) && defined(EAI_NONAME) +#define HAVE_GETADDRINFO +#endif + +// getaddrinfo support? +#ifndef HAVE_GETADDRINFO + #error Boink + + // Renamed to advoid type clashing.. (for debugging) + struct addrinfo_emu + { + int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */ + int ai_family; /* PF_xxx */ + int ai_socktype; /* SOCK_xxx */ + int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ + size_t ai_addrlen; /* length of ai_addr */ + char *ai_canonname; /* canonical name for nodename */ + struct sockaddr *ai_addr; /* binary address */ + struct addrinfo *ai_next; /* next structure in linked list */ + }; + #define addinfo addrinfo_emu + + int getaddrinfo(const char *nodename, const char *servname, + const struct addrinfo *hints, + struct addrinfo **res); + void freeaddrinfo(struct addrinfo *ai); + + #ifndef AI_PASSIVE + #define AI_PASSIVE (1<<1) + #endif + + #ifndef EAI_NONAME + #define EAI_NONAME -1 + #define EAI_AGAIN -2 + #define EAI_FAIL -3 + #define EAI_NODATA -4 + #define EAI_FAMILY -5 + #define EAI_SOCKTYPE -6 + #define EAI_SERVICE -7 + #define EAI_ADDRFAMILY -8 + #define EAI_ADDRFAMILY -8 + #define EAI_SYSTEM -10 + #endif + +#endif + +// getnameinfo support (glibc2.0 has getaddrinfo only) +#ifndef HAVE_GETNAMEINFO + + int getnameinfo(const struct sockaddr *sa, socklen_t salen, + char *host, size_t hostlen, + char *serv, size_t servlen, + int flags); +#endif + +#endif -- cgit v1.2.3