From 0837bd25607acd90944a4bfded58d582371ba112 Mon Sep 17 00:00:00 2001 From: Arch Librarian Date: Mon, 20 Sep 2004 16:53:53 +0000 Subject: [PATCH] Multiprotocol connect Author: jgg Date: 1999-05-29 03:25:03 GMT Multiprotocol connect --- methods/connect.cc | 143 +++++++++++++++++++++++++++++++++++++++++++++ methods/connect.h | 19 ++++++ methods/ftp.cc | 74 +++-------------------- methods/http.cc | 72 ++--------------------- methods/makefile | 8 +-- 5 files changed, 180 insertions(+), 136 deletions(-) create mode 100644 methods/connect.cc create mode 100644 methods/connect.h diff --git a/methods/connect.cc b/methods/connect.cc new file mode 100644 index 000000000..a7ef8c669 --- /dev/null +++ b/methods/connect.cc @@ -0,0 +1,143 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: connect.cc,v 1.1 1999/05/29 03:25:03 jgg Exp $ +/* ###################################################################### + + Connect - Replacement connect call + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include "connect.h" +#include +#include + +#include +#include +#include + +// Internet stuff +#include +#include +#include +#include + +#include "rfc2553emu.h" + /*}}}*/ + +static string LastHost; +static int LastPort = 0; +static struct addrinfo *LastHostAddr = 0; +static struct addrinfo *LastUsed = 0; + +// DoConnect - Attempt a connect operation /*{{{*/ +// --------------------------------------------------------------------- +/* This helper function attempts a connection to a single address. */ +static bool DoConnect(struct addrinfo *Addr,string Host, + unsigned long TimeOut,int &Fd,pkgAcqMethod *Owner) +{ + // Show a status indicator + char Name[NI_MAXHOST]; + Name[0] = 0; + getnameinfo(Addr->ai_addr,Addr->ai_addrlen, + Name,sizeof(Name),0,0,NI_NUMERICHOST); + Owner->Status("Connecting to %s (%s)",Host.c_str(),Name); + + // Get a socket + if ((Fd = socket(Addr->ai_family,Addr->ai_socktype, + Addr->ai_protocol)) < 0) + return _error->Errno("socket","Could not create a socket"); + + SetNonBlock(Fd,true); + if (connect(Fd,Addr->ai_addr,Addr->ai_addrlen) < 0 && + errno != EINPROGRESS) + return _error->Errno("connect","Cannot initiate the connection " + "to %s (%s).",Host.c_str(),Name); + + /* This implements a timeout for connect by opening the connection + nonblocking */ + if (WaitFd(Fd,true,TimeOut) == false) + return _error->Error("Could not connect to %s (%s), " + "connection timed out",Host.c_str(),Name); + + // Check the socket for an error condition + unsigned int Err; + unsigned int Len = sizeof(Err); + if (getsockopt(Fd,SOL_SOCKET,SO_ERROR,&Err,&Len) != 0) + return _error->Errno("getsockopt","Failed"); + + if (Err != 0) + return _error->Error("Could not connect to %s (%s).",Host.c_str(),Name); + + return true; +} + /*}}}*/ +// Connect - Connect to a server /*{{{*/ +// --------------------------------------------------------------------- +/* Performs a connection to the server */ +bool Connect(string Host,int Port,const char *Service,int &Fd, + unsigned long TimeOut,pkgAcqMethod *Owner) +{ + if (_error->PendingError() == true) + return false; + + /* 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 || LastPort != Port) + { + Owner->Status("Connecting to %s",Host.c_str()); + + // Lookup the host + char S[300]; + if (Port != 0) + snprintf(S,sizeof(S),"%u",Port); + else + snprintf(S,sizeof(S),"%s",Service); + + // 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; + LastPort = Port; + LastUsed = 0; + } + + // Get the printable IP address + struct addrinfo *CurHost = LastHostAddr; + if (LastUsed != 0) + CurHost = LastUsed; + + while (CurHost != 0) + { + if (DoConnect(CurHost,Host,TimeOut,Fd,Owner) == true) + { + LastUsed = CurHost; + return true; + } + close(Fd); + Fd = -1; + + CurHost = CurHost->ai_next; + LastUsed = 0; + if (CurHost != 0) + _error->Discard(); + } + + return false; +} + /*}}}*/ diff --git a/methods/connect.h b/methods/connect.h new file mode 100644 index 000000000..3af499236 --- /dev/null +++ b/methods/connect.h @@ -0,0 +1,19 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: connect.h,v 1.1 1999/05/29 03:25:03 jgg Exp $ +/* ###################################################################### + + Connect - Replacement connect call + + ##################################################################### */ + /*}}}*/ +#ifndef CONNECT_H +#define CONNECT_H + +#include +#include + +bool Connect(string To,int Port,const char *Service,int &Fd, + unsigned long TimeOut,pkgAcqMethod *Owner); + +#endif diff --git a/methods/ftp.cc b/methods/ftp.cc index efc50c205..7bd0a3e18 100644 --- a/methods/ftp.cc +++ b/methods/ftp.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: ftp.cc,v 1.12 1999/05/28 07:04:45 jgg Exp $ +// $Id: ftp.cc,v 1.13 1999/05/29 03:25:03 jgg Exp $ /* ###################################################################### HTTP Aquire Method - This is the FTP aquire method for APT. @@ -36,6 +36,7 @@ #include #include "rfc2553emu.h" +#include "connect.h" #include "ftp.h" /*}}}*/ @@ -81,9 +82,6 @@ void FTPConn::Close() // --------------------------------------------------------------------- /* Connect to the server using a non-blocking connection and perform a login. */ -string LastHost; -int LastPort = 0; -struct addrinfo *LastHostAddr = 0; bool FTPConn::Open(pkgAcqMethod *Owner) { // Use the already open connection if possible. @@ -125,70 +123,14 @@ bool FTPConn::Open(pkgAcqMethod *Owner) Port = Proxy.Port; Host = Proxy.Host; } - - /* 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 || LastPort != Port) - { - Owner->Status("Connecting to %s",Host.c_str()); - - // Lookup the host - char S[30] = "ftp"; - 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; - LastPort = Port; - } - - // Get the printable IP address - char Name[NI_MAXHOST]; - Name[0] = 0; - getnameinfo(LastHostAddr->ai_addr,LastHostAddr->ai_addrlen, - Name,sizeof(Name),0,0,NI_NUMERICHOST); - Owner->Status("Connecting to %s (%s)",Host.c_str(),Name); + // Connect to the remote server + if (Connect(Host,Port,"ftp",ServerFd,TimeOut,Owner) == false) + return false; + socklen_t Len = sizeof(Peer); + if (getpeername(ServerFd,(sockaddr *)&Peer,&Len) != 0) + return _error->Errno("getpeername","Unable to determine the peer name"); - // Get a socket - if ((ServerFd = socket(LastHostAddr->ai_family,LastHostAddr->ai_socktype, - LastHostAddr->ai_protocol)) < 0) - return _error->Errno("socket","Could not create a socket"); - SetNonBlock(ServerFd,true); - if (connect(ServerFd,LastHostAddr->ai_addr,LastHostAddr->ai_addrlen) < 0 && - errno != EINPROGRESS) - return _error->Errno("connect","Cannot initiate the connection " - "to %s (%s).",Host.c_str(),Name); - Peer = *((struct sockaddr_in *)LastHostAddr->ai_addr); - - /* This implements a timeout for connect by opening the connection - nonblocking */ - if (WaitFd(ServerFd,true,TimeOut) == false) - return _error->Error("Could not connect to %s (%s), " - "connection timed out",Host.c_str(),Name); - unsigned int Err; - unsigned int Len = sizeof(Err); - if (getsockopt(ServerFd,SOL_SOCKET,SO_ERROR,&Err,&Len) != 0) - return _error->Errno("getsockopt","Failed"); - if (Err != 0) - return _error->Error("Could not connect to %s (%s).",Host.c_str(),Name); - Owner->Status("Logging in"); return Login(); } diff --git a/methods/http.cc b/methods/http.cc index 4e659ccd6..f014193a0 100644 --- a/methods/http.cc +++ b/methods/http.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: http.cc,v 1.33 1999/05/28 07:04:45 jgg Exp $ +// $Id: http.cc,v 1.34 1999/05/29 03:25:03 jgg Exp $ /* ###################################################################### HTTP Aquire Method - This is the HTTP aquire method for APT. @@ -41,11 +41,9 @@ #include // Internet stuff -/*#include -#include -#include -#include */ +#include +#include "connect.h" #include "rfc2553emu.h" #include "http.h" @@ -306,67 +304,9 @@ bool ServerState::Open() Host = Proxy.Host; } - /* 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 || LastPort != Port) - { - Owner->Status("Connecting to %s",Host.c_str()); - - // Lookup the host - 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; - LastPort = Port; - } - - // Get the printable IP address - char Name[NI_MAXHOST]; - Name[0] = 0; - getnameinfo(LastHostAddr->ai_addr,LastHostAddr->ai_addrlen, - Name,sizeof(Name),0,0,NI_NUMERICHOST); - Owner->Status("Connecting to %s (%s)",Host.c_str(),Name); - - // Get a socket - if ((ServerFd = socket(LastHostAddr->ai_family,LastHostAddr->ai_socktype, - LastHostAddr->ai_protocol)) < 0) - return _error->Errno("socket","Could not create a socket"); - SetNonBlock(ServerFd,true); - if (connect(ServerFd,LastHostAddr->ai_addr,LastHostAddr->ai_addrlen) < 0 && - errno != EINPROGRESS) - return _error->Errno("connect","Cannot initiate the connection " - "to %s (%s).",Host.c_str(),Name); - - /* This implements a timeout for connect by opening the connection - nonblocking */ - if (WaitFd(ServerFd,true,TimeOut) == false) - return _error->Error("Could not connect to %s (%s), " - "connection timed out",Host.c_str(),Name); - unsigned int Err; - unsigned int Len = sizeof(Err); - if (getsockopt(ServerFd,SOL_SOCKET,SO_ERROR,&Err,&Len) != 0) - return _error->Errno("getsockopt","Failed"); - if (Err != 0) - return _error->Error("Could not connect to %s (%s).",Host.c_str(),Name); + // Connect to the remote server + if (Connect(Host,Port,"http",ServerFd,TimeOut,Owner) == false) + return false; return true; } diff --git a/methods/makefile b/methods/makefile index 4345307e2..32ec3464d 100644 --- a/methods/makefile +++ b/methods/makefile @@ -36,14 +36,14 @@ include $(PROGRAM_H) # The http method PROGRAM=http -SLIBS = -lapt-pkg +SLIBS = -lapt-pkg LIB_MAKES = apt-pkg/makefile -SOURCE = http.cc rfc2553emu.cc +SOURCE = http.cc rfc2553emu.cc connect.cc include $(PROGRAM_H) # The ftp method PROGRAM=ftp -SLIBS = -lapt-pkg +SLIBS = -lapt-pkg LIB_MAKES = apt-pkg/makefile -SOURCE = ftp.cc rfc2553emu.cc +SOURCE = ftp.cc rfc2553emu.cc connect.cc include $(PROGRAM_H) -- 2.45.2