[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#668948: marked as done (apt: Proposal for a better handling of timeouted connection)



Your message dated Wed, 03 Jan 2018 23:03:57 +0000
with message-id <E1eWs4j-0000J1-8W@fasolo.debian.org>
and subject line Bug#668948: fixed in apt 1.6~alpha6
has caused the Debian Bug report #668948,
regarding apt: Proposal for a better handling of timeouted connection
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
668948: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=668948
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: apt
Version: 0.8.15.10+nmu1
Severity: wishlist

  Hi,

  My laptop is running is different network environments. Sometimes
there is only IPv4, sometimes IPv4 and IPv6 and somtimes IPv4 and
broken IPv6.
  I do not want to always desactivate IPv6 (mostly because I want
to be able to test it). However, when I'm in a broken IPv6 network
environment (IPv6 address setup on my laptop but broken routers),
it is really painful to wait for APT timeout on the IPv6 address
before APT switch to an IPv4. My main mirror is ftp.fr.debian.org
that has both IPv4 and IPv6 addresses:
vdanjean@eyak:/tmp$ host ftp.fr.debian.org
ftp.fr.debian.org is an alias for debian.proxad.net.
debian.proxad.net has address 212.27.32.66
debian.proxad.net has IPv6 address 2a01:e0c:1:1598::2

  So, today, I tried to get the sources of apt and implement
what is described here:
http://www.isc.org/community/blog/201101/how-to-connect-to-a-multi-homed-server-over-tcp
I based my code on the "Select based sample code" provided as APT already uses
select and I patched methods/connect.cc

The patch in in attachment to this message. The patch has not yet
the required quality to be added to APT. However, it allows me to
test the feature and I would say that I'm really enjoyed (ie, even
if the patch does not go upstream, I will keep it locally for me).
Currently, the patch allows to come back to the previous behavior
by defining the APT_SEQUENTIAL_CONNECT environment variable.

So, I've several questions:
- would you be interested by such kind of parallel connection?
- if no, why?
- if yes:
  * the license/copyright would need to be adapted (my code is
    based on http://www.isc.org/files/imce/select-connect_0.c )
  * the code need to be simplify (no need to keep the old behavior)
  * the code need to be checked, in particular for error handling.
    As connections occurs in parallel, I'm not sure what must be
    done with _error. With my current code, _error->Errno can be
    called lots of times for example.
  * if this behavior is kept, is it really necessary to keep the
    "LastUsed" variable? I keep it in my code but I'm not sure
    it is really needed anymore. And getting rid of it would
    simplify the code.

  So, let me know what you think of this.

  Regards,
   Vincent

-- Package-specific info:

-- (/etc/apt/preferences present, but not submitted) --


-- (/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.3.0-trunk-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  2010.08.28
ii  gnupg                   1.4.12-4
ii  libc6                   2.13-27
ii  libgcc1                 1:4.6.3-1
ii  libstdc++6              4.6.3-1
ii  zlib1g                  1:1.2.6.dfsg-2

apt recommends no packages.

Versions of packages apt suggests:
ii  apt-doc         <none>
ii  aptitude        0.6.5-1
ii  bzip2           1.0.6-1
ii  dpkg-dev        1.16.2
ii  python-apt      0.8.3+nmu1
ii  synaptic        0.75.6
ii  xz-lzma [lzma]  5.1.1alpha+20110809-3

-- no debconf information
diff --git a/methods/connect.cc b/methods/connect.cc
index a5af1f1..b3b1a80 100644
--- a/methods/connect.cc
+++ b/methods/connect.cc
@@ -37,6 +37,8 @@ static 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<string> bad_addr;
@@ -125,6 +127,190 @@ static bool DoConnect(struct addrinfo *Addr,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,
+		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 = { TimeOut, 0 };
+  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 */
@@ -154,6 +340,7 @@ bool Connect(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.
@@ -201,6 +388,17 @@ bool Connect(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.
@@ -208,6 +406,15 @@ bool Connect(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)

--- End Message ---
--- Begin Message ---
Source: apt
Source-Version: 1.6~alpha6

We believe that the bug you reported is fixed in the latest version of
apt, which is due to be installed in the Debian FTP archive.

A summary of the changes between this version and the previous one is
attached.

Thank you for reporting the bug, which will now be closed.  If you
have further comments please address them to 668948@bugs.debian.org,
and the maintainer will reopen the bug report if appropriate.

Debian distribution maintenance software
pp.
Julian Andres Klode <jak@debian.org> (supplier of updated apt package)

(This message was generated automatically at their request; if you
believe that there is a problem with it please contact the archive
administrators by mailing ftpmaster@ftp-master.debian.org)


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

Format: 1.8
Date: Wed, 03 Jan 2018 22:33:37 +0000
Source: apt
Binary: apt libapt-pkg5.0 libapt-inst2.0 apt-doc libapt-pkg-dev libapt-pkg-doc apt-utils apt-transport-https
Architecture: source
Version: 1.6~alpha6
Distribution: unstable
Urgency: medium
Maintainer: APT Development Team <deity@lists.debian.org>
Changed-By: Julian Andres Klode <jak@debian.org>
Description:
 apt        - commandline package manager
 apt-doc    - documentation for APT
 apt-transport-https - transitional package for https support
 apt-utils  - package management related utility programs
 libapt-inst2.0 - deb package format runtime library
 libapt-pkg-dev - development files for APT's libapt-pkg and libapt-inst
 libapt-pkg-doc - documentation for APT development
 libapt-pkg5.0 - package management runtime library
Closes: 668948 849636 881875 882850 884922
Changes:
 apt (1.6~alpha6) unstable; urgency=medium
 .
   [ Julian Andres Klode ]
   * Add Breaks: aptitude (<< 0.8.10) for gzip method removal
   * Also look at https_proxy for https URLs
   * Run wrap-and-sort
   * Translate shared documentation parts again
   * tests: Improve handling profiling messages on CI
   * connect: Store the IP used when picking a connection
   * Add rapid "happy eyeballs" connection fallback (RFC 8305) (Closes: #668948)
     (LP: #1308200)
 .
   [ David Kalnischkies ]
   * allow multivalue fields in deb822 sources to be folded (Closes: 881875)
   * support COLUMNS environment variable in apt tools
   * allow apt_auth.conf(5) to be translated
   * if insecure repo is allowed continue on all http errors
   * don't auto-switch candidate if installed is good enough
   * update libapt-pkg symbols file
   * explicitly name token in auth.conf parsing error
   * fix over-calculating dpkg commandline length
   * avoid some useless casts reported by -Wuseless-cast
   * deal with floats without old-style cast
   * support multiline values in LookupTag
   * mark some 500 HTTP codes as transient acquire errors
   * report transient errors as transient errors
   * implement Acquire::Retries support for all items
   * give the methods more metadata about the files to acquire
   * implement fallback to alternative URIs for all items
   * do not remap current files if nullptrs in cache generation
   * apt.daily: remove unused dbus signal for apt update (Closes: 849636)
   * Support cleartext signed InRelease files with CRLF line endings.
     Thanks to Lukas Wunner for detailed report & initial patch! (Closes: 884922)
   * document http options in new apt-transport-http manpage
   * document https options in new apt-transport-https manpage
   * refactor message generation for methods
   * allow a method to request auxiliary files
   * reimplement and simplify mirror:// method
   * require methods to request AuxRequest capability at startup
   * add tag-based control over mirror choices from the list
   * non-local mirrorlists shouldn't redirect to local
   * add apt-transport-mirror manpage
 .
   [ Milo Casagrande ]
   * Italian program translation update (Closes: 882850)
 .
   [ Christian Göttsche ]
   * apt.daily: fix several "shellcheck" annotations
Checksums-Sha1:
 991742019c2d59f7fa878567832e4e6d9d22e187 2710 apt_1.6~alpha6.dsc
 98e4ffac61185514093dd91a5ecdd82111693acf 2111456 apt_1.6~alpha6.tar.xz
 34a34ae208e3301f0ecc48a3ba5c9ff0a5971be2 7329 apt_1.6~alpha6_source.buildinfo
Checksums-Sha256:
 0a34f3594e568e58ffda9bea341e5065ed181756be8dc24ac72ac5c0fa269b01 2710 apt_1.6~alpha6.dsc
 ddcdb5f3ec1922f6a42a18b9ea2fd4945e945510d26a548c16de4874aa30b817 2111456 apt_1.6~alpha6.tar.xz
 1138e999717a841d3269184642a040a2ed85d4b79658ec604d08f3bd478e30b5 7329 apt_1.6~alpha6_source.buildinfo
Files:
 6c80816b16bc76917c34c9a6d344fcfe 2710 admin important apt_1.6~alpha6.dsc
 3d49ac109b935909a313a4ff2a39a5af 2111456 admin important apt_1.6~alpha6.tar.xz
 f64c46dcf5454c007ff340c88453b8e9 7329 admin important apt_1.6~alpha6_source.buildinfo

-----BEGIN PGP SIGNATURE-----

iQIsBAEBCgAWBQJaTVsfDxxqYWtAZGViaWFuLm9yZwAKCRDXPDnlZYCzhtdND/0S
AS49Sxsrsk/AJXncGnqggyPd15ozIfCux9F4B+8BGH+r57RsQkHaVblpNx0O7M10
IV/Z9KmdW8f+/0Ik8Lswjw6FsJNvjVInba65KwwesyxJxTsygcIWDDRSFpMzYUYi
oUOmg9JVzOkkFAt6VM8PCiqGdjxjiuJ1wbP3cFjM1Grx/Eibi5gWtJBWYnthz3Av
kAzB3t+dTLmjDp4Qmg+f8ysN/bi2cev6rsIonup7r7psiIYkbBnPyqlmN1ONPgZf
nC5JQsCglCs985DH4COnTZula41Xfe3gn49tnk9Y1UM1n0IsVQF7TDSYJYuiKsiC
0Q/qIzMDB7r7H4FGpTV5bYngzL0wk5hnLphp7Vavg8LbWheUatFMqBnp6G/3stGq
CrfGd6AC16lGrVbhnRn9Sxee3AOViQP+6WtNQ6rXI0gqQod8P7YCoRoi6Kmoo83y
CONusd4q6WOk6tJVs39hdOsYsdZ3HKz3ylmWJVaXeTZGt3PbYN0B/QrIx63yo/+d
+knjkKKU7iKavjpJdD8CDgJiSDErAw/Yn5SQ3C80LKkgfQaCASvbHvTRNOtL6mQX
cl9dbSnhYjKqHzg4Trn9sYUm1kCNgFZW5catON2A+NTomWO4BMykEb7nHHUz8yF2
ylHG/sj1P6SXKpsELF6Cc69cN5dsGHtUyiMGn4gdkw==
=uj2J
-----END PGP SIGNATURE-----

--- End Message ---

Reply to: