Package: xmms
Version: 1.2.10-2
Followup-For: Bug #211842

The problem is that xmms opens an async. socket to the server. It
doesn't wait for a response if the particular socket works or not. For
example, if a server has AAAA and A address, and first lookup yields
AAAA, xmms will send SYN to server but doesn't wait for connection to be
established. Well, it does, but too late to go though other addresses.
This will cause all sorts of problems if you have multiple, not just
AAAA, addresses. If the first one fails, xmms will not go to the next
address on the list.

I've attached a patch that will fix the problem. Please apply.

The code will need be to be cleaned up a bit (I'll try to do that later
on sometime). The IPV4 code is not needed and the #ifdef IPV6 are not
needed either because there is *nothing* IPV6 specific in the connection
code.

- Adam


-- System Information:
Debian Release: 3.1
  APT prefers unstable
  APT policy: (500, 'unstable'), (1, 'experimental')
Architecture: i386 (i686)
Kernel: Linux 2.6.10-1-k7
Locale: LANG=C, LC_CTYPE=C (charmap=ANSI_X3.4-1968)

Versions of packages xmms depends on:
ii  libc6                    2.3.2.ds1-20    GNU C Library: Shared libraries an
ii  libglib1.2               1.2.10-9        The GLib library of C routines
ii  libgtk1.2                1.2.10-17       The GIMP Toolkit set of widgets fo
ii  libice6                  4.3.0.dfsg.1-12 Inter-Client Exchange library
ii  libsm6                   4.3.0.dfsg.1-12 X Window System Session Management
ii  libx11-6                 4.3.0.dfsg.1-12 X Window System protocol client li
ii  libxext6                 4.3.0.dfsg.1-12 X Window System miscellaneous exte
ii  libxi6                   4.3.0.dfsg.1-12 X Window System Input extension li
ii  xlibs                    4.3.0.dfsg.1-12 X Keyboard Extension (XKB) configu

-- no debconf information
--- xmms-1.2.10/Input/mpg123/http.c	2003-12-07 11:09:49.000000000 -0600
+++ xmms-1.2.10/Input/mpg123/http.c	2005-02-24 12:17:14.278071456 -0600
@@ -364,6 +364,7 @@
 		g_snprintf(service, 6, "%d", cport);
 		memset(&hints, 0, sizeof(hints));
 		hints.ai_socktype = SOCK_STREAM;
+		hints.ai_family = PF_UNSPEC;
 		if (! getaddrinfo(chost, service, &hints, &res0)) {
 			eof = TRUE;
 			for (res = res0; res; res = res->ai_next) {
@@ -375,10 +376,35 @@
 				g_free(status);
 				((struct sockaddr_in6 *)res->ai_addr)->sin6_port = htons(cport);
 				if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
+					int connected = 0;
+					
 					if (errno != EINPROGRESS) {
 						close(sock);
 						continue;
 					}
+					/* We are EINPROGRESS. We need to wait if we can actually connect before we can actually
+					 * say that we have a connection as multiple addresses are possible for a host and and 
+					 * we should not fail to connect if one address fails.
+					 */
+					while (going) {
+						fd_set set;
+						FD_ZERO(&set);
+						FD_SET(sock, &set);
+
+						tv.tv_sec = 0;
+						tv.tv_usec = 10000;
+						if (select(sock + 1, NULL, &set, NULL, &tv) > 0) {
+							err_len = sizeof (error);
+							getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &err_len);
+							if (error == 0)
+								connected = 1;
+							break;
+						}
+						else if( errno == EBADF || error == ENOMEM )
+							break; /* Select failures - break to avoid possible infinite loop */
+					}
+					if( !connected )
+						continue;
 				}
 				eof = FALSE;
 				break;
--- xmms-1.2.10/Input/vorbis/http.c	2003-09-04 15:59:05.000000000 -0500
+++ xmms-1.2.10/Input/vorbis/http.c	2005-02-24 12:20:22.571446512 -0600
@@ -319,6 +319,7 @@
 		g_snprintf(service, 6, "%d", cport);
 		memset(&hints, 0, sizeof(hints));
 		hints.ai_socktype = SOCK_STREAM;
+		hints.ai_family = PF_UNSPEC;
 		if (! getaddrinfo(chost, service, &hints, &res0)) {
 			eof = TRUE;
 			for (res = res0; res; res = res->ai_next) {
@@ -330,10 +331,35 @@
 				g_free(status);
 				((struct sockaddr_in6 *)res->ai_addr)->sin6_port = htons(cport);
 				if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
+					int connected = 0;
+					
 					if (errno != EINPROGRESS) {
 						close(sock);
 						continue;
 					}
+					/* We are EINPROGRESS. We need to wait if we can actually connect before we can actually
+					 * say that we have a connection as multiple addresses are possible for a host and and 
+					 * we should not fail to connect if one address fails.
+					 */
+					while (going) {
+						fd_set set;
+						FD_ZERO(&set);
+						FD_SET(sock, &set);
+
+						tv.tv_sec = 0;
+						tv.tv_usec = 10000;
+						if (select(sock + 1, NULL, &set, NULL, &tv) > 0) {
+							err_len = sizeof (error);
+							getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &err_len);
+							if (error == 0)
+								connected = 1;
+							break;
+						}
+						else if( errno == EBADF || error == ENOMEM )
+							break; /* Select failures - break to avoid possible infinite loop */
+					}
+					if( !connected )
+						continue;
 				}
 				eof = FALSE;
 				break;

Reply via email to