Package: apt Version: 0.9.3 Followup-For: Bug #668948 Any comments on my proposal? In any case, here is an updated patch for apt 0.9.3.
Regards, Vincent -- Package-specific info: -- /etc/apt/preferences -- -- (/etc/apt/sources.list present, but not submitted) -- -- System Information: Debian Release: wheezy/sid APT prefers unstable APT policy: (500, 'unstable'), (500, 'testing'), (500, 'stable'), (1, 'experimental') Architecture: amd64 (x86_64) Kernel: Linux 3.2.0-2-amd64 (SMP w/8 CPU cores) Locale: LANG=fr_FR.UTF-8, LC_CTYPE=fr_FR.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash Versions of packages apt depends on: ii debian-archive-keyring 2012.2 ii gnupg 1.4.12-4 ii libapt-pkg4.12 0.9.3+nmu1 ii libc6 2.13-32 ii libgcc1 1:4.7.0-8 ii libstdc++6 4.7.0-8 apt recommends no packages. Versions of packages apt suggests: ii apt-doc <none> ii aptitude 0.6.7-1 ii dpkg-dev 1.16.3+0~1333384407.7~1.gbp45fe25 ii python-apt 0.8.4 ii synaptic 0.75.10 ii xz-utils 5.1.1alpha+20110809-3 -- no debconf information
diff --git a/methods/connect.cc b/methods/connect.cc index 9a092a4..c04ccb0 100644 --- a/methods/connect.cc +++ b/methods/connect.cc @@ -41,6 +41,8 @@ static std::string LastHost; static int LastPort = 0; static struct addrinfo *LastHostAddr = 0; static struct addrinfo *LastUsed = 0; +static int nbHosts = 0; +static int use_parallel_connect = 0; // Set of IP/hostnames that we timed out before or couldn't resolve static std::set<std::string> bad_addr; @@ -129,6 +131,191 @@ static bool DoConnect(struct addrinfo *Addr,std::string Host, return true; } /*}}}*/ +// connect_to_host - Connect to a server /*{{{*/ +// --------------------------------------------------------------------- +/* Performs a connection to the server */ +#define TIMEOUT 500 +static bool +connect_to_host(struct addrinfo *StartHost,struct addrinfo *FirstHostAddr, + std::string Host,int count,int &Fd, + unsigned long TimeOut,pkgAcqMethod * Owner) { + struct addrinfo *Addr, *NextAddr, **Addrs = NULL; + int fd = -1, n, i, j, max = -1, *fds; + struct timeval *timeout, timeout0 = { 0, TIMEOUT * 1000}, + timeout1 = { 0, 0 }; + timeout1.tv_sec = TimeOut; + fd_set fdset, wrset; + // Show a status indicator + char Name[NI_MAXHOST]; + char Service[NI_MAXSERV]; + + fds = new int[count]();//calloc(count, sizeof(*fds)); + if (fds == NULL) { + _error->Errno("calloc",_("Cannot allocate %d file descriptors"),count); + return false; + } + Addrs = new struct addrinfo *[count](); + if (Addrs == NULL) { + _error->Errno("calloc",_("Cannot allocate %d pointers"),count); + free(fds); + return false; + } + FD_ZERO(&fdset); + for(Addr = StartHost, i = 0, count = 0; Addr != NULL; Addr = NextAddr) { + NextAddr = Addr; + + // Ignore UNIX domain sockets + do { + NextAddr = NextAddr->ai_next; + } while (NextAddr != 0 && NextAddr->ai_family == AF_UNIX); + + /* If we reached the end of the search list then wrap around to the + start */ + if (NextAddr == 0) + NextAddr = FirstHostAddr; + + // Reached the end of the search cycle + if (NextAddr == StartHost) + NextAddr = NULL; + + + Name[0] = 0; + Service[0] = 0; + getnameinfo(Addr->ai_addr,Addr->ai_addrlen, + Name,sizeof(Name),Service,sizeof(Service), + NI_NUMERICHOST|NI_NUMERICSERV); + Owner->Status(_("Connecting to %s (%s)"),Host.c_str(),Name); + + fd = socket(Addr->ai_family, Addr->ai_socktype, Addr->ai_protocol); + if (fd == -1) { + /* + * If AI_ADDRCONFIG is not supported we will get + * EAFNOSUPPORT returned. Behave as if the address + * was not there. + */ + if (errno != EAFNOSUPPORT) { + _error->Errno("socket",_("Could not create a socket for %s (f=%u t=%u p=%u)"), + Name,Addr->ai_family,Addr->ai_socktype,Addr->ai_protocol); + } else if (NextAddr != NULL) + continue; + } else if (fd >= FD_SETSIZE) { + close(fd); + } else { + SetNonBlock(fd,true); + if (connect(fd, Addr->ai_addr, Addr->ai_addrlen) == -1) { + if (errno != EINPROGRESS) { + _error->Errno("connect",_("Cannot initiate the connection " + "to %s:%s (%s)."),Host.c_str(),Service,Name); + close(fd); + } else { + /* + * Record the information for this descriptor. + */ + fds[i] = fd; + Addrs[i] = Addr; + FD_SET(fd, &fdset); + if (max == -1 || fd > max) + max = fd; + count++; + i++; + } + } else { + /* + * We connected without blocking. + */ + LastUsed = Addr; + goto done; + } + } + + if (count == 0) + continue; + + //assert(max != -1); + do { + if (Addr->ai_next != NULL) + timeout = &timeout0; + else + timeout = &timeout1; + + /* The write bit is set on both success and failure. */ + wrset = fdset; + n = select(max + 1, NULL, &wrset, NULL, timeout); + if (n == 0) { + timeout0.tv_usec >>= 1; + break; + } + if (n < 0) { + if (errno == EAGAIN || errno == EINTR) + continue; + _error->Errno("select", _("Cannot select")); + fd = -1; + goto done; + } + for (fd = 0; fd <= max; fd++) { + if (FD_ISSET(fd, &wrset)) { + socklen_t len; + int err; + for (j = 0; j < i; j++) + if (fds[j] == fd) + break; + //assert(j < i); + /* + * Test to see if the connect + * succeeded. + */ + len = sizeof(err); + n = getsockopt(fd, SOL_SOCKET, + SO_ERROR, &err, &len); + if (n != 0 || err != 0) { + if (n != 0) { + _error->Errno("getsockopt",_("Failed")); + } else { + errno = err; + if(errno == ECONNREFUSED) + Owner->SetFailReason("ConnectionRefused"); + else if (errno == ETIMEDOUT) + Owner->SetFailReason("ConnectionTimedOut"); + _error->Errno("connect",_("Could not connect to %s:%s (%s)."), + Host.c_str(),Service,Name); + } + close(fd); + FD_CLR(fd, &fdset); + fds[j] = -1; + count--; + continue; + } + /* Connect succeeded. */ + LastUsed = Addrs[j]; + goto done; + } + } + } while (timeout == &timeout1 && count != 0); + } + + /* We failed to connect. */ + fd = -1; + + done: + /* Close all other descriptors we have created. */ + for (j = 0; j < i; j++) + if (fds[j] != fd && fds[j] != -1) { + close(fds[j]); + } + + /* Free everything. */ + if (fds) delete[](fds); + if (Addrs) delete[](Addrs); + + if (fd != -1) { + Fd=fd; + _error->Discard(); + return true; + } + + return false; +} + /*}}}*/ // Connect - Connect to a server /*{{{*/ // --------------------------------------------------------------------- /* Performs a connection to the server */ @@ -158,6 +345,7 @@ bool Connect(std::string Host,int Port,const char *Service,int DefPort,int &Fd, freeaddrinfo(LastHostAddr); LastHostAddr = 0; LastUsed = 0; + nbHosts = 0; } // We only understand SOCK_STREAM sockets. @@ -205,6 +393,17 @@ bool Connect(std::string Host,int Port,const char *Service,int DefPort,int &Fd, LastHost = Host; LastPort = Port; + + /* + * Work out how many possible IP we could use. + */ + struct addrinfo *res; + for (res = LastHostAddr; res; res = res->ai_next) { + // Ignore UNIX domain sockets + if (res->ai_family == AF_UNIX) + continue; + nbHosts++; + } } // When we have an IP rotation stay with the last IP. @@ -212,6 +411,15 @@ bool Connect(std::string Host,int Port,const char *Service,int DefPort,int &Fd, if (LastUsed != 0) CurHost = LastUsed; + if (use_parallel_connect == 0) { + use_parallel_connect=1; + if (getenv("APT_SEQUENTIAL_CONNECT") != NULL) + use_parallel_connect=-1; + } + if (use_parallel_connect == 1) { + return connect_to_host(CurHost,LastHostAddr,Host,nbHosts,Fd,TimeOut,Owner); + } + while (CurHost != 0) { if (DoConnect(CurHost,Host,TimeOut,Fd,Owner) == true)