Package: nbd
Version: 2.9.14-3
Severity: normal
Tags: patch

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

I have provide the initial patch for IPv6 support in
nbd-{server, client} which the nbd-server able to
serve in both IPv4 and IPv6 requests.

Patch is attached.

The client can connect to the server that listen on
IPv6 or IPv4 like this on command line

# nbd-client ::1...@11111 /dev/nbd0
or
# nbd-client 127.0....@11111 /dev/nbd0

Substitute the port separator from ":" to "@".

Please test and also advice me if you have seen
something wrong in the code.

Regards,
Neutron Soutmun

- -- System Information:
Debian Release: squeeze/sid
  APT prefers unstable
  APT policy: (500, 'unstable')
Architecture: amd64 (x86_64)

Kernel: Linux 2.6.32-2-amd64 (SMP w/2 CPU cores)
Locale: LANG=th_TH.UTF-8, LC_CTYPE=th_TH.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/bash

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)

iEYEARECAAYFAkufbTEACgkQ1k7Ar9TO/TfBjwCfUfGLSRwg3Mlo0TvcubZQzQbY
7lYAniCEFhJAIdChCnli0NC4as5VNzTW
=FF47
-----END PGP SIGNATURE-----
diff -u nbd-2.9.14/nbd-server.c nbd-2.9.14/nbd-server.c
--- nbd-2.9.14/nbd-server.c
+++ nbd-2.9.14/nbd-server.c
@@ -49,6 +49,10 @@
  * 11/02/2004 - Doxygenified the source, modularized it a bit. Needs a 
  * 	lot more work, but this is a start. Wouter Verhelst
  * 	<wou...@debian.org>
+ * 16/03/2010 - Add IPv6 support.
+ * 	Kitt Tientanopajai <k...@kitty.in.th>
+ *	Neutron Soutmun <neo.neut...@gmail.com>
+ *	Suriya Soutmun <darkso...@gmail.com>
  */
 
 /* Includes LFS defines, which defines behaviours of some of the following
@@ -70,8 +74,8 @@
 #include <signal.h>		/* sigaction */
 #include <errno.h>
 #include <netinet/tcp.h>
-#include <netinet/in.h>		/* sockaddr_in, htons, in_addr */
-#include <netdb.h>		/* hostent, gethostby*, getservby* */
+#include <netinet/in.h>
+#include <netdb.h>
 #include <syslog.h>
 #include <unistd.h>
 #include <stdio.h>
@@ -178,6 +182,7 @@
 	char* authname;      /**< filename of the authorization file */
 	int flags;           /**< flags associated with this exported file */
 	int socket;	     /**< The socket of this server. */
+	int socket_family;   /**< family of the socket */
 	VIRT_STYLE virtstyle;/**< The style of virtualization, if any */
 	uint8_t cidrlen;     /**< The length of the mask when we use
 				  CIDR-style virtualization */
@@ -338,7 +343,7 @@
  */
 void usage() {
 	printf("This is nbd-server version " VERSION "\n");
-	printf("Usage: [ip:]port file_to_export [size][kKmM] [-l authorize_file] [-r] [-m] [-c] [-C configuration file] [-p PID file name] [-o section name]\n"
+	printf("Usage: [...@]port file_to_export [size][kKmM] [-l authorize_file] [-r] [-m] [-c] [-C configuration file] [-p PID file name] [-o section name]\n"
 	       "\t-r|--read-only\t\tread only\n"
 	       "\t-m|--multi-file\t\tmultiple file\n"
 	       "\t-c|--copy-on-write\tcopy on write\n"
@@ -417,7 +422,7 @@
 			/* non-option argument */
 			switch(nonspecial++) {
 			case 0:
-				addr_port=g_strsplit(optarg, ":", 2);
+				addr_port=g_strsplit(optarg, "@", 2);
 				if(addr_port[1]) {
 					serve->port=strtol(addr_port[1], NULL, 0);
 					serve->listenaddr=g_strdup(addr_port[0]);
@@ -526,6 +531,46 @@
 }
 
 /**
+ * duplicate server 
+ * @param s the old server we want to duplicate
+ **/
+SERVER* dup_serve(SERVER *s) {
+	SERVER *serve = NULL;
+
+	serve=g_new0(SERVER, 1);
+	if (serve == NULL)
+		return NULL;
+
+	memset(serve,0,sizeof(SERVER));
+
+	if (s->exportname)
+		serve->exportname = g_strdup(s->exportname);
+
+	serve->expected_size = s->expected_size;
+
+	if (s->listenaddr)
+		serve->listenaddr = g_strdup(s->listenaddr);
+
+	serve->port = s->port;	
+
+	if (s->authname)
+		serve->authname = strdup(s->authname);
+
+	serve->flags = s->flags;
+	serve->socket = serve->socket;
+	serve->socket_family = serve->socket_family;
+	serve->cidrlen = s->cidrlen;
+
+	if (s->prerun)
+		serve->prerun = g_strdup(s->prerun);
+
+	if (s->postrun)
+		serve->postrun = g_strdup(s->postrun);
+
+	return serve;
+}
+
+/**
  * Parse the config file.
  *
  * @param f the name of the config file
@@ -539,6 +584,7 @@
 	const char* DEFAULT_ERROR = "Could not parse %s in group %s: %s";
 	const char* MISSING_REQUIRED_ERROR = "Could not find required value %s in group %s: %s";
 	SERVER s;
+	SERVER *ns = NULL;
 	gchar *virtstyle=NULL;
 	PARAM lp[] = {
 		{ "exportname", TRUE,	PARAM_STRING, 	NULL, 0 },
@@ -690,7 +736,17 @@
 		if(i>0) {
 			if(!s.listenaddr) {
 				s.listenaddr = g_strdup("0.0.0.0");
+				s.socket_family = AF_UNSPEC;
+
+			  ns = dup_serve (&s);	
+				if (ns) {
+					ns->socket_family = AF_INET6;
+					g_array_append_val(retval, *ns);
+					free(ns);
+					ns = NULL;
+				}	
 			}
+
 			g_array_append_val(retval, s);
 		}
 #ifndef WITH_SDP
@@ -1346,15 +1402,34 @@
 void set_peername(int net, CLIENT *client) {
 	struct sockaddr_storage addrin;
 	struct sockaddr_storage netaddr;
+	struct sockaddr_in  *netaddr4 = NULL;
+	struct sockaddr_in6 *netaddr6 = NULL;
 	size_t addrinlen = sizeof( addrin );
-	char *peername;
-	char *netname;
-	char *tmp;
+	struct addrinfo hints;
+	struct addrinfo *ai = NULL;
+	char peername[NI_MAXHOST];
+	char netname[NI_MAXHOST];
+	char *tmp = NULL;
 	int i;
+	int e;
+	int shift;
 
-	if (getpeername(net, (struct sockaddr *) &addrin, (socklen_t *)&addrinlen) < 0)
+	if (getpeername(net, (struct sockaddr *)&addrin, (socklen_t *)&addrinlen) < 0)
 		err("getsockname failed: %m");
-	peername = g_strdup(inet_ntoa(addrin.sin_addr));
+
+	getnameinfo((struct sockaddr *)&addrin, (socklen_t)addrinlen,
+		peername, sizeof (peername), NULL, 0, NI_NUMERICHOST);
+
+	memset(&hints, '\0', sizeof (hints));
+	hints.ai_flags = AI_ADDRCONFIG;
+	e = getaddrinfo(peername, NULL, &hints, &ai);
+
+	if(e != 0) {
+		fprintf(stderr, "getaddrinfo failed: %s", gai_strerror(e));
+		freeaddrinfo(ai);
+		return;
+	}
+
 	switch(client->server->virtstyle) {
 		case VIRT_NONE:
 			client->exportname=g_strdup(client->server->exportname);
@@ -1370,18 +1445,42 @@
 			break;
 		case VIRT_CIDR:
 			memcpy(&netaddr, &addrin, addrinlen);
-			netaddr.sin_addr.s_addr>>=32-(client->server->cidrlen);
-			netaddr.sin_addr.s_addr<<=32-(client->server->cidrlen);
-			netname = inet_ntoa(netaddr.sin_addr);
-			tmp=g_strdup_printf("%s/%s", netname, peername);
-			client->exportname=g_strdup_printf(client->server->exportname, tmp);
+			if(ai->ai_family == AF_INET) {
+				netaddr4 = (struct sockaddr_in *)&netaddr;
+				(netaddr4->sin_addr).s_addr>>=32-(client->server->cidrlen);
+				(netaddr4->sin_addr).s_addr<<=32-(client->server->cidrlen);
+
+				getnameinfo((struct sockaddr *) netaddr4, (socklen_t) addrinlen,
+							netname, sizeof (netname), NULL, 0, NI_NUMERICHOST);
+				tmp=g_strdup_printf("%s/%s", netname, peername);
+			}else if(ai->ai_family == AF_INET6) {
+				netaddr6 = (struct sockaddr_in6 *)&netaddr;
+
+				shift = 128-(client->server->cidrlen);
+				i = 3;
+				while(shift >= 32) {
+					((netaddr6->sin6_addr).s6_addr32[i])=0;
+					shift-=32;
+					i--;
+				}
+				(netaddr6->sin6_addr).s6_addr32[i]>>=shift;
+				(netaddr6->sin6_addr).s6_addr32[i]<<=shift;
+
+				getnameinfo((struct sockaddr *)netaddr6, (socklen_t)addrinlen,
+					    netname, sizeof(netname), NULL, 0, NI_NUMERICHOST);
+				tmp=g_strdup_printf("%s/%s", netname, peername);
+			}
+
+			if(tmp != NULL)
+			  client->exportname=g_strdup_printf(client->server->exportname, tmp);
+
 			break;
 	}
 
+	freeaddrinfo(ai);
 	msg4(LOG_INFO, "connect from %s, assigned file is %s", 
 	     peername, client->exportname);
 	client->clientname=g_strdup(peername);
-	g_free(peername);
 }
 
 /**
@@ -1493,23 +1592,53 @@
  **/
 void setup_serve(SERVER *serve) {
 	struct sockaddr_storage addrin;
+	struct addrinfo hints;
+	struct addrinfo *ai = NULL;
 	struct sigaction sa;
 	int addrinlen = sizeof(addrin);
 	int sock_flags;
-	int af;
 #ifndef sun
 	int yes=1;
 #else
 	char yes='1';
 #endif /* sun */
+	gchar *port = NULL;
+	int e;
+
+	memset(&hints,'\0',sizeof(hints));
+	hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG | AI_NUMERICSERV;
+	hints.ai_socktype = SOCK_STREAM;
+
+	port = g_strdup_printf ("%d", serve->port);
+	if (port == NULL)
+		return;
+
+	if(g_strcmp0(serve->listenaddr, "0.0.0.0") == 0) {
+		hints.ai_family = serve->socket_family;
+		e = getaddrinfo(NULL,port,&hints,&ai); 
+	} else {
+		e = getaddrinfo(serve->listenaddr,port,&hints,&ai); 
+	}
+
+	g_free(port);
+
+	if(e!=0) {
+		freeaddrinfo(ai);
+		return;
+	}
+
+	if(serve->socket_family == AF_UNSPEC)
+		serve->socket_family = ai->ai_family;
 
-	af = AF_INET;
 #ifdef WITH_SDP
-	if ((serve->flags) && F_SDP) {
-		af = AF_INET_SDP;
+	if((serve->flags) && F_SDP) {
+		if (ai->ai_family == AF_INET)
+			ai->ai_family = AF_INET_SDP;
+		else (ai->ai_family == AF_INET6)
+			ai->ai_family = AF_INET6_SDP;
 	}
 #endif
-	if ((serve->socket = socket(af, SOCK_STREAM, IPPROTO_TCP)) < 0)
+	if ((serve->socket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0)
 		err("socket: %m");
 
 	/* lose the pesky "Address already in use" error message */
@@ -1529,20 +1658,15 @@
 	}
 
 	DEBUG("Waiting for connections... bind, ");
-	addrin.sin_family = AF_INET;
-#ifdef WITH_SDP
-	if(serve->flags & F_SDP) {
-		addrin.sin_family = AF_INET_SDP;
-	}
-#endif
-	addrin.sin_port = htons(serve->port);
-	if(!inet_aton(serve->listenaddr, &(addrin.sin_addr)))
-		err("could not parse listen address");
-	if (bind(serve->socket, (struct sockaddr *) &addrin, addrinlen) < 0)
+	e = bind(serve->socket, ai->ai_addr, ai->ai_addrlen);
+	if (e != 0 && errno != EADDRINUSE)
 		err("bind: %m");
 	DEBUG("listen, ");
 	if (listen(serve->socket, 1) < 0)
 		err("listen: %m");
+
+	freeaddrinfo (ai);
+
 	sa.sa_handler = sigchld_handler;
 	sigemptyset(&sa.sa_mask);
 	sa.sa_flags = SA_RESTART;
diff -u nbd-2.9.14/debian/changelog nbd-2.9.14/debian/changelog
--- nbd-2.9.14/debian/changelog
+++ nbd-2.9.14/debian/changelog
@@ -1,3 +1,12 @@
+nbd (1:2.9.14-3.1) unstable; urgency=low
+
+  * Non-maintainer upload.
+  * debian/patches/01_ipv6_support.patch: Add IPv6 support.
+    thanks Kitt for initial nbd-client patch, Suriya for dup_serve() patch.
+    (Closes: #382189)
+    
+ -- Neutron Soutmun <neo.neut...@gmail.com>  Mon, 15 Mar 2010 12:08:01 +0700
+
 nbd (1:2.9.14-3) unstable; urgency=low
 
   * Be more careful about what we unmount. Closes: #534728.
diff -u nbd-2.9.14/debian/patches/01_ipv6_support.patch nbd-2.9.14/debian/patches/01_ipv6_support.patch
--- nbd-2.9.14/debian/patches/01_ipv6_support.patch
+++ nbd-2.9.14/debian/patches/01_ipv6_support.patch
@@ -1,8 +1,97 @@
 Index: b/nbd-server.c
 ===================================================================
---- a/nbd-server.c	2010-03-15 12:06:12.000000000 +0700
-+++ b/nbd-server.c	2010-03-15 12:06:33.000000000 +0700
-@@ -1344,8 +1344,8 @@
+--- a/nbd-server.c	2010-03-15 14:00:15.000000000 +0700
++++ b/nbd-server.c	2010-03-16 14:56:34.000000000 +0700
+@@ -49,6 +49,10 @@
+  * 11/02/2004 - Doxygenified the source, modularized it a bit. Needs a 
+  * 	lot more work, but this is a start. Wouter Verhelst
+  * 	<wou...@debian.org>
++ * 16/03/2010 - Add IPv6 support.
++ * 	Kitt Tientanopajai <k...@kitty.in.th>
++ *	Neutron Soutmun <neo.neut...@gmail.com>
++ *	Suriya Soutmun <darkso...@gmail.com>
+  */
+ 
+ /* Includes LFS defines, which defines behaviours of some of the following
+@@ -70,8 +74,8 @@
+ #include <signal.h>		/* sigaction */
+ #include <errno.h>
+ #include <netinet/tcp.h>
+-#include <netinet/in.h>		/* sockaddr_in, htons, in_addr */
+-#include <netdb.h>		/* hostent, gethostby*, getservby* */
++#include <netinet/in.h>
++#include <netdb.h>
+ #include <syslog.h>
+ #include <unistd.h>
+ #include <stdio.h>
+@@ -178,6 +182,7 @@
+ 	char* authname;      /**< filename of the authorization file */
+ 	int flags;           /**< flags associated with this exported file */
+ 	int socket;	     /**< The socket of this server. */
++	int socket_family;   /**< family of the socket */
+ 	VIRT_STYLE virtstyle;/**< The style of virtualization, if any */
+ 	uint8_t cidrlen;     /**< The length of the mask when we use
+ 				  CIDR-style virtualization */
+@@ -338,7 +343,7 @@
+  */
+ void usage() {
+ 	printf("This is nbd-server version " VERSION "\n");
+-	printf("Usage: [ip:]port file_to_export [size][kKmM] [-l authorize_file] [-r] [-m] [-c] [-C configuration file] [-p PID file name] [-o section name]\n"
++	printf("Usage: [...@]port file_to_export [size][kKmM] [-l authorize_file] [-r] [-m] [-c] [-C configuration file] [-p PID file name] [-o section name]\n"
+ 	       "\t-r|--read-only\t\tread only\n"
+ 	       "\t-m|--multi-file\t\tmultiple file\n"
+ 	       "\t-c|--copy-on-write\tcopy on write\n"
+@@ -417,7 +422,7 @@
+ 			/* non-option argument */
+ 			switch(nonspecial++) {
+ 			case 0:
+-				addr_port=g_strsplit(optarg, ":", 2);
++				addr_port=g_strsplit(optarg, "@", 2);
+ 				if(addr_port[1]) {
+ 					serve->port=strtol(addr_port[1], NULL, 0);
+ 					serve->listenaddr=g_strdup(addr_port[0]);
+@@ -691,6 +696,7 @@
+ 			if(!s.listenaddr) {
+ 				s.listenaddr = g_strdup("0.0.0.0");
+ 			}
++			s.socket_family = AF_UNSPEC;
+ 			g_array_append_val(retval, s);
+ 		}
+ #ifndef WITH_SDP
+@@ -708,7 +714,32 @@
+ 	g_key_file_free(cfile);
+ 	return retval;
+ }
++/**
++ * duplicate server 
++ * @param s the old server we want to duplicate
++ **/
++SERVER* dup_serve(SERVER *s) {
++	SERVER *serve = NULL;
++
++	serve=g_new0(SERVER, 1);
++	if (serve == NULL)
++		return NULL;
++
++	memset(serve,0,sizeof(SERVER));
++	serve->exportname = g_strdup(s->exportname);
++	serve->expected_size = s->expected_size;
++	serve->listenaddr = g_strdup(s->listenaddr);
++	serve->port = s->port;	
++	serve->authname = strdup(s->authname);
++	serve->flags = s->flags;
++	serve->socket = serve->socket;
++	serve->socket_family = serve->socket_family;
++	serve->cidrlen = s->cidrlen;
++	serve->prerun = g_strdup(s->prerun);
++	serve->postrun = g_strdup(s->postrun);
+ 
++	return serve;
++}
+ /**
+  * Signal handler for SIGCHLD
+  * @param s the signal we're handling (must be SIGCHLD, or something
+@@ -1344,17 +1375,36 @@
   * stored in client->clientname.
   **/
  void set_peername(int net, CLIENT *client) {
@@ -10,10 +99,92 @@
 -	struct sockaddr_in netaddr;
 +	struct sockaddr_storage addrin;
 +	struct sockaddr_storage netaddr;
++	struct sockaddr_in  *netaddr4 = NULL;
++	struct sockaddr_in6 *netaddr6 = NULL;
  	size_t addrinlen = sizeof( addrin );
- 	char *peername;
- 	char *netname;
-@@ -1396,7 +1396,7 @@
+-	char *peername;
+-	char *netname;
+-	char *tmp;
++	struct addrinfo hints;
++	struct addrinfo *ai = NULL;
++	char peername[NI_MAXHOST];
++	char netname[NI_MAXHOST];
++	char *tmp = NULL;
+ 	int i;
++	int e;
++	int shift;
+ 
+-	if (getpeername(net, (struct sockaddr *) &addrin, (socklen_t *)&addrinlen) < 0)
++	if (getpeername(net, (struct sockaddr *)&addrin, (socklen_t *)&addrinlen) < 0)
+ 		err("getsockname failed: %m");
+-	peername = g_strdup(inet_ntoa(addrin.sin_addr));
++
++	getnameinfo((struct sockaddr *)&addrin, (socklen_t)addrinlen,
++		peername, sizeof (peername), NULL, 0, NI_NUMERICHOST);
++
++	memset(&hints, '\0', sizeof (hints));
++	hints.ai_flags = AI_ADDRCONFIG;
++	e = getaddrinfo(peername, NULL, &hints, &ai);
++
++	if(e != 0) {
++		fprintf(stderr, "getaddrinfo failed: %s", gai_strerror(e));
++		freeaddrinfo(ai);
++		return;
++	}
++
+ 	switch(client->server->virtstyle) {
+ 		case VIRT_NONE:
+ 			client->exportname=g_strdup(client->server->exportname);
+@@ -1370,18 +1420,42 @@
+ 			break;
+ 		case VIRT_CIDR:
+ 			memcpy(&netaddr, &addrin, addrinlen);
+-			netaddr.sin_addr.s_addr>>=32-(client->server->cidrlen);
+-			netaddr.sin_addr.s_addr<<=32-(client->server->cidrlen);
+-			netname = inet_ntoa(netaddr.sin_addr);
+-			tmp=g_strdup_printf("%s/%s", netname, peername);
+-			client->exportname=g_strdup_printf(client->server->exportname, tmp);
++			if(ai->ai_family == AF_INET) {
++				netaddr4 = (struct sockaddr_in *)&netaddr;
++				(netaddr4->sin_addr).s_addr>>=32-(client->server->cidrlen);
++				(netaddr4->sin_addr).s_addr<<=32-(client->server->cidrlen);
++
++				getnameinfo((struct sockaddr *) netaddr4, (socklen_t) addrinlen,
++							netname, sizeof (netname), NULL, 0, NI_NUMERICHOST);
++				tmp=g_strdup_printf("%s/%s", netname, peername);
++			}else if(ai->ai_family == AF_INET6) {
++				netaddr6 = (struct sockaddr_in6 *)&netaddr;
++
++				shift = 128-(client->server->cidrlen);
++				i = 3;
++				while(shift >= 32) {
++					((netaddr6->sin6_addr).s6_addr32[i])=0;
++					shift-=32;
++					i--;
++				}
++				(netaddr6->sin6_addr).s6_addr32[i]>>=shift;
++				(netaddr6->sin6_addr).s6_addr32[i]<<=shift;
++
++				getnameinfo((struct sockaddr *)netaddr6, (socklen_t)addrinlen,
++					    netname, sizeof(netname), NULL, 0, NI_NUMERICHOST);
++				tmp=g_strdup_printf("%s/%s", netname, peername);
++			}
++
++			if(tmp != NULL)
++			  client->exportname=g_strdup_printf(client->server->exportname, tmp);
++
+ 			break;
+ 	}
+ 
++	freeaddrinfo(ai);
+ 	msg4(LOG_INFO, "connect from %s, assigned file is %s", 
+ 	     peername, client->exportname);
+ 	client->clientname=g_strdup(peername);
+-	g_free(peername);
+ }
+ 
+ /**
+@@ -1396,7 +1470,7 @@
   * Loop through the available servers, and serve them. Never returns.
   **/
  int serveloop(GArray* servers) {
@@ -25,9 +196,207 @@
-@@ -1492,7 +1492,7 @@
+@@ -1492,24 +1566,54 @@
   * @param serve the server we want to connect.
   **/
  void setup_serve(SERVER *serve) {
 -	struct sockaddr_in addrin;
 +	struct sockaddr_storage addrin;
++	struct addrinfo hints;
++	struct addrinfo *ai = NULL;
  	struct sigaction sa;
  	int addrinlen = sizeof(addrin);
  	int sock_flags;
+-	int af;
+ #ifndef sun
+ 	int yes=1;
+ #else
+ 	char yes='1';
+ #endif /* sun */
++	gchar *port = NULL;
++	int e;
++
++	memset(&hints,'\0',sizeof(hints));
++	hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG | AI_NUMERICSERV;
++	hints.ai_socktype = SOCK_STREAM;
++
++	port = g_strdup_printf ("%d", serve->port);
++	if (port == NULL)
++		return;
++
++	if(g_strcmp0(serve->listenaddr, "0.0.0.0") == 0) {
++		hints.ai_family = serve->socket_family;
++		e = getaddrinfo(NULL,port,&hints,&ai); 
++	} else {
++		e = getaddrinfo(serve->listenaddr,port,&hints,&ai); 
++	}
++
++	g_free(port);
++
++	if(e!=0) {
++		freeaddrinfo(ai);
++		return;
++	}
++
++	if(serve->socket_family == AF_UNSPEC)
++		serve->socket_family = ai->ai_family;
+ 
+-	af = AF_INET;
+ #ifdef WITH_SDP
+-	if ((serve->flags) && F_SDP) {
+-		af = AF_INET_SDP;
++	if((serve->flags) && F_SDP) {
++		if (ai->ai_family == AF_INET)
++			ai->ai_family = AF_INET_SDP;
++		else (ai->ai_family == AF_INET6)
++			ai->ai_family = AF_INET6_SDP;
+ 	}
+ #endif
+-	if ((serve->socket = socket(af, SOCK_STREAM, IPPROTO_TCP)) < 0)
++	if ((serve->socket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0)
+ 		err("socket: %m");
+ 
+ 	/* lose the pesky "Address already in use" error message */
+@@ -1529,20 +1633,15 @@
+ 	}
+ 
+ 	DEBUG("Waiting for connections... bind, ");
+-	addrin.sin_family = AF_INET;
+-#ifdef WITH_SDP
+-	if(serve->flags & F_SDP) {
+-		addrin.sin_family = AF_INET_SDP;
+-	}
+-#endif
+-	addrin.sin_port = htons(serve->port);
+-	if(!inet_aton(serve->listenaddr, &(addrin.sin_addr)))
+-		err("could not parse listen address");
+-	if (bind(serve->socket, (struct sockaddr *) &addrin, addrinlen) < 0)
++	e = bind(serve->socket, ai->ai_addr, ai->ai_addrlen);
++	if (e != 0 && errno != EADDRINUSE)
+ 		err("bind: %m");
+ 	DEBUG("listen, ");
+ 	if (listen(serve->socket, 1) < 0)
+ 		err("listen: %m");
++
++	freeaddrinfo (ai);
++
+ 	sa.sa_handler = sigchld_handler;
+ 	sigemptyset(&sa.sa_mask);
+ 	sa.sa_flags = SA_RESTART;
+@@ -1560,9 +1659,20 @@
+  **/
+ void setup_servers(GArray* servers) {
+ 	int i;
++	SERVER *s;
++	SERVER *ns;
+ 
+ 	for(i=0;i<servers->len;i++) {
+-		setup_serve(&(g_array_index(servers, SERVER, i)));
++		s = &(g_array_index(servers, SERVER, i));
++		setup_serve(s);
++		if(g_strcmp0(s->listenaddr, "0.0.0.0") == 0 && s->socket_family == AF_INET) {
++			ns = dup_serve (s);	
++			if (ns) {
++				ns->socket_family = AF_INET6;
++				g_array_append_val(servers,*ns);
++				free(ns);
++			}	
++		}
+ 	}
+ 	children=g_hash_table_new_full(g_int_hash, g_int_equal, NULL, destroy_pid_t);
+ }
+Index: b/nbd-client.c
+===================================================================
+--- a/nbd-client.c	2010-03-16 14:20:34.000000000 +0700
++++ b/nbd-client.c	2010-03-16 14:53:25.000000000 +0700
+@@ -11,6 +11,10 @@
+  * Version 2.1 - Check for disconnection before INIT_PASSWD is received
+  * 	to make errormsg a bit more helpful in case the server can't
+  * 	open the exported file.
++ * 16/03/2010 - Add IPv6 support.
++ * 	Kitt Tientanopajai <k...@kitty.in.th>
++ *	Neutron Soutmun <neo.neut...@gmail.com>
++ *	Suriya Soutmun <darkso...@gmail.com>
+  */
+ 
+ #include "config.h"
+@@ -21,8 +25,8 @@
+ #include <sys/types.h>
+ #include <unistd.h>
+ #include <netinet/tcp.h>
+-#include <netinet/in.h>		/* sockaddr_in, htons, in_addr */
+-#include <netdb.h>		/* hostent, gethostby*, getservby* */
++#include <netinet/in.h>
++#include <netdb.h>
+ #include <stdio.h>
+ #include <fcntl.h>
+ #include <syslog.h>
+@@ -67,33 +71,54 @@
+ 
+ int opennet(char *name, int port, int sdp) {
+ 	int sock;
+-	struct sockaddr_in xaddrin;
+-	int xaddrinlen = sizeof(xaddrin);
+-	struct hostent *hostn;
+-	int af;
+-
+-	hostn = gethostbyname(name);
+-	if (!hostn)
+-		err("Gethostname failed: %h\n");
++	char portstr[6];
++	struct addrinfo hints;
++	struct addrinfo *ai = NULL;
++	struct addrinfo *rp = NULL;
++	int e;
++
++	snprintf(portstr, sizeof(portstr), "%d", port);
++
++	memset(&hints,'\0',sizeof(hints));
++	hints.ai_family = AF_UNSPEC;
++	hints.ai_socktype = SOCK_STREAM;
++	hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
++	hints.ai_protocol = IPPROTO_TCP;
++
++	e = getaddrinfo(name, portstr, &hints, &ai);
++
++	if(e != 0) {
++		freeaddrinfo(ai);
++		return -1;
++	}
+ 
+-	af = AF_INET;
+ 	if(sdp) {
+ #ifdef WITH_SDP
+-		af = AF_INET_SDP;
++	if (ai->ai_family == AF_INET)
++		ai->ai_family = AF_INET_SDP;
++	else (ai->ai_family == AF_INET6)
++		ai->ai_family = AF_INET6_SDP;
+ #else
+ 		err("Can't do SDP: I was not compiled with SDP support!");
+ #endif
+ 	}
+-	if ((sock = socket(af, SOCK_STREAM, IPPROTO_TCP)) < 0)
+-		err("Socket failed: %m");
+ 
+-	xaddrin.sin_family = af;
+-	xaddrin.sin_port = htons(port);
+-	xaddrin.sin_addr.s_addr = *((int *) hostn->h_addr);
+-	if ((connect(sock, (struct sockaddr *) &xaddrin, xaddrinlen) < 0))
+-		err("Connect: %m");
++	for(rp = ai; rp != NULL; rp = rp->ai_next) {
++		sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
++
++		if(sock == -1)
++			continue;	/* error */
++
++		if(connect(sock, rp->ai_addr, rp->ai_addrlen) != -1)
++			break;		/* success */
++	}
++
++	if (rp == NULL)
++		err("Socket failed: %m");
+ 
+ 	setmysockopt(sock);
++
++	freeaddrinfo(ai);
+ 	return sock;
+ }
+ 
only in patch2:
unchanged:
--- nbd-2.9.14.orig/nbd-client.c
+++ nbd-2.9.14/nbd-client.c
@@ -11,6 +11,10 @@
  * Version 2.1 - Check for disconnection before INIT_PASSWD is received
  * 	to make errormsg a bit more helpful in case the server can't
  * 	open the exported file.
+ * 16/03/2010 - Add IPv6 support.
+ * 	Kitt Tientanopajai <k...@kitty.in.th>
+ *	Neutron Soutmun <neo.neut...@gmail.com>
+ *	Suriya Soutmun <darkso...@gmail.com>
  */
 
 #include "config.h"
@@ -21,8 +25,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 #include <netinet/tcp.h>
-#include <netinet/in.h>		/* sockaddr_in, htons, in_addr */
-#include <netdb.h>		/* hostent, gethostby*, getservby* */
+#include <netinet/in.h>
+#include <netdb.h>
 #include <stdio.h>
 #include <fcntl.h>
 #include <syslog.h>
@@ -67,33 +71,54 @@
 
 int opennet(char *name, int port, int sdp) {
 	int sock;
-	struct sockaddr_in xaddrin;
-	int xaddrinlen = sizeof(xaddrin);
-	struct hostent *hostn;
-	int af;
-
-	hostn = gethostbyname(name);
-	if (!hostn)
-		err("Gethostname failed: %h\n");
+	char portstr[6];
+	struct addrinfo hints;
+	struct addrinfo *ai = NULL;
+	struct addrinfo *rp = NULL;
+	int e;
+
+	snprintf(portstr, sizeof(portstr), "%d", port);
+
+	memset(&hints,'\0',sizeof(hints));
+	hints.ai_family = AF_UNSPEC;
+	hints.ai_socktype = SOCK_STREAM;
+	hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
+	hints.ai_protocol = IPPROTO_TCP;
+
+	e = getaddrinfo(name, portstr, &hints, &ai);
+
+	if(e != 0) {
+		freeaddrinfo(ai);
+		return -1;
+	}
 
-	af = AF_INET;
 	if(sdp) {
 #ifdef WITH_SDP
-		af = AF_INET_SDP;
+	if (ai->ai_family == AF_INET)
+		ai->ai_family = AF_INET_SDP;
+	else (ai->ai_family == AF_INET6)
+		ai->ai_family = AF_INET6_SDP;
 #else
 		err("Can't do SDP: I was not compiled with SDP support!");
 #endif
 	}
-	if ((sock = socket(af, SOCK_STREAM, IPPROTO_TCP)) < 0)
-		err("Socket failed: %m");
 
-	xaddrin.sin_family = af;
-	xaddrin.sin_port = htons(port);
-	xaddrin.sin_addr.s_addr = *((int *) hostn->h_addr);
-	if ((connect(sock, (struct sockaddr *) &xaddrin, xaddrinlen) < 0))
-		err("Connect: %m");
+	for(rp = ai; rp != NULL; rp = rp->ai_next) {
+		sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+
+		if(sock == -1)
+			continue;	/* error */
+
+		if(connect(sock, rp->ai_addr, rp->ai_addrlen) != -1)
+			break;		/* success */
+	}
+
+	if (rp == NULL)
+		err("Socket failed: %m");
 
 	setmysockopt(sock);
+
+	freeaddrinfo(ai);
 	return sock;
 }
 
only in patch2:
unchanged:
--- nbd-2.9.14.orig/.pc/01_ipv6_support.patch/nbd-tester-client.c
+++ nbd-2.9.14/.pc/01_ipv6_support.patch/nbd-tester-client.c
@@ -0,0 +1,352 @@
+/*
+ * Test client to test the NBD server. Doesn't do anything useful, except
+ * checking that the server does, actually, work.
+ *
+ * Note that the only 'real' test is to check the client against a kernel. If
+ * it works here but does not work in the kernel, then that's most likely a bug
+ * in this program and/or in nbd-server.
+ *
+ * Copyright(c) 2006  Wouter Verhelst
+ *
+ * This program is Free Software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, in version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <syslog.h>
+#include <unistd.h>
+#include "config.h"
+#include "lfs.h"
+#define MY_NAME "nbd-tester-client"
+#include "cliserv.h"
+
+#include <netinet/in.h>
+#include <glib.h>
+
+static gchar errstr[1024];
+const static int errstr_len=1024;
+
+typedef enum {
+	CONNECTION_TYPE_NONE,
+	CONNECTION_TYPE_CONNECT,
+	CONNECTION_TYPE_INIT_PASSWD,
+	CONNECTION_TYPE_CLISERV,
+	CONNECTION_TYPE_FULL,
+} CONNECTION_TYPE;
+
+typedef enum {
+	CONNECTION_CLOSE_PROPERLY,
+	CONNECTION_CLOSE_FAST,
+} CLOSE_TYPE;
+
+inline int read_all(int f, void *buf, size_t len) {
+	ssize_t res;
+	size_t retval=0;
+
+	while(len>0) {
+		if((res=read(f, buf, len)) <=0) {
+			snprintf(errstr, errstr_len, "Read failed: %s", strerror(errno));
+			return -1;
+		}
+		len-=res;
+		buf+=res;
+		retval+=res;
+	}
+	return retval;
+}
+
+int setup_connection(gchar *hostname, int port, CONNECTION_TYPE ctype) {
+	int sock;
+	struct hostent *host;
+	struct sockaddr_in addr;
+	char buf[256];
+	u64 tmp64;
+
+	sock=0;
+	if(ctype<CONNECTION_TYPE_CONNECT)
+		goto end;
+	if((sock=socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))<0) {
+		strncpy(errstr, strerror(errno), errstr_len);
+		goto err;
+	}
+	setmysockopt(sock);
+	if(!(host=gethostbyname(hostname))) {
+		strncpy(errstr, strerror(errno), errstr_len);
+		goto err_open;
+	}
+	addr.sin_family=AF_INET;
+	addr.sin_port=htons(port);
+	addr.sin_addr.s_addr=*((int *) host->h_addr);
+	if((connect(sock, (struct sockaddr *)&addr, sizeof(addr))<0)) {
+		strncpy(errstr, strerror(errno), errstr_len);
+		goto err_open;
+	}
+	if(ctype<CONNECTION_TYPE_INIT_PASSWD)
+		goto end;
+	if(read_all(sock, buf, strlen(INIT_PASSWD))<0) {
+		snprintf(errstr, errstr_len, "Could not read INIT_PASSWD: %s",
+				strerror(errno));
+		goto err_open;
+	}
+	if(strlen(buf)==0) {
+		snprintf(errstr, errstr_len, "Server closed connection");
+		goto err_open;
+	}
+	if(strncmp(buf, INIT_PASSWD, strlen(INIT_PASSWD))) {
+		snprintf(errstr, errstr_len, "INIT_PASSWD does not match");
+		goto err_open;
+	}
+	if(ctype<CONNECTION_TYPE_CLISERV)
+		goto end;
+	if(read_all(sock, &tmp64, sizeof(tmp64))<0) {
+		snprintf(errstr, errstr_len, "Could not read cliserv_magic: %s",
+				strerror(errno));
+		goto err_open;
+	}
+	tmp64=ntohll(tmp64);
+	if(tmp64 != cliserv_magic) {
+		strncpy(errstr, "cliserv_magic does not match", errstr_len);
+		goto err_open;
+	}
+	if(ctype<CONNECTION_TYPE_FULL)
+		goto end;
+	/* The information we get now contains information on sizes. If
+	 * we're here, that means we want a 'working' connection, but
+	 * we're not interested in the sizes. So, read them but throw
+	 * the values away. We need to read the size of the device (a
+	 * 64bit integer) plus the reserved fields (128 bytes; should
+	 * all be zeroes).
+	 */
+	read_all(sock, buf, sizeof(tmp64)+128);
+	goto end;
+err_open:
+	close(sock);
+err:
+	sock=-1;
+end:
+	return sock;
+}
+
+int close_connection(int sock, CLOSE_TYPE type) {
+	struct nbd_request req;
+	u64 counter=0;
+
+	switch(type) {
+		case CONNECTION_CLOSE_PROPERLY:
+			req.magic=htonl(NBD_REQUEST_MAGIC);
+			req.type=htonl(NBD_CMD_DISC);
+			memcpy(&(req.handle), &(counter), sizeof(counter));
+			counter++;
+			req.from=0;
+			req.len=0;
+			if(write(sock, &req, sizeof(req))<0) {
+				snprintf(errstr, errstr_len, "Could not write to socket: %s", strerror(errno));
+				return -1;
+			}
+		case CONNECTION_CLOSE_FAST:
+			if(close(sock)<0) {
+				snprintf(errstr, errstr_len, "Could not close socket: %s", strerror(errno));
+				return -1;
+			}
+			break;
+		default:
+			g_critical("Your compiler is on crack!"); /* or I am buggy */
+			return -1;
+	}
+	return 0;
+}
+
+int read_packet_check_header(int sock, size_t datasize, long long int curhandle) {
+	struct nbd_reply rep;
+	int retval=0;
+	char buf[datasize];
+
+	read_all(sock, &rep, sizeof(rep));
+	rep.magic=ntohl(rep.magic);
+	rep.error=ntohl(rep.error);
+	if(rep.magic!=NBD_REPLY_MAGIC) {
+		snprintf(errstr, errstr_len, "Received package with incorrect reply_magic. Index of sent packages is %lld (0x%llX), received handle is %lld (0x%llX). Received magic 0x%lX, expected 0x%lX", curhandle, curhandle, *((u64*)rep.handle), *((u64*)rep.handle), (long unsigned int)rep.magic, (long unsigned int)NBD_REPLY_MAGIC);
+		retval=-1;
+		goto end;
+	}
+	if(rep.error) {
+		snprintf(errstr, errstr_len, "Received error from server: %ld (0x%lX). Handle is %lld (0x%llX).", (long int)rep.error, (long unsigned int)rep.error, (long long int)(*((u64*)rep.handle)), *((u64*)rep.handle));
+		retval=-1;
+		goto end;
+	}
+	read_all(sock, &buf, datasize);
+
+end:
+	return retval;
+}
+
+int throughput_test(gchar* hostname, int port, int sock, char sock_is_open, char close_sock) {
+	long long int i;
+	char buf[1024];
+	struct nbd_request req;
+	u64 size;
+	int requests=0;
+	fd_set set;
+	struct timeval tv;
+	struct timeval start;
+	struct timeval stop;
+	float timespan;
+	int speed;
+	char speedchar[2] = { '\0', '\0' };
+	int retval=0;
+	size_t tmp;
+	signed int do_write=TRUE;
+
+	size=0;
+	if(!sock_is_open) {
+		if((sock=setup_connection(hostname, port, CONNECTION_TYPE_CLISERV))<0) {
+			g_warning("Could not open socket: %s", errstr);
+			retval=-1;
+			goto err;
+		}
+	} else {
+		/* Assume the file is at least 4k in size. Not much of a test
+		 * this way, but, well. */
+		size=4096;
+	}
+	if((tmp=read_all(sock, &size, sizeof(u64)))<0) {
+		retval=-1;
+		snprintf(errstr, errstr_len, "Could not read from socket: %s", strerror(errno));
+		goto err_open;
+	}
+	if(tmp==0) {
+		retval=-1;
+		snprintf(errstr, errstr_len, "Server closed connection unexpectedly when trying to read size of device in throughput test");
+		goto err;
+	}
+	read_all(sock,&buf,128);
+	size=ntohll(size);
+	req.magic=htonl(NBD_REQUEST_MAGIC);
+	req.type=htonl(NBD_CMD_READ);
+	req.len=htonl(1024);
+	if(gettimeofday(&start, NULL)<0) {
+		retval=-1;
+		snprintf(errstr, errstr_len, "Could not measure start time: %s", strerror(errno));
+		goto err_open;
+	}
+	for(i=0;i+1024<=size;i+=1024) {
+		if(do_write) {
+			memcpy(&(req.handle),&i,sizeof(i));
+			req.from=htonll(i);
+			write(sock, &req, sizeof(req));
+			printf("Requests(+): %d\n", ++requests);
+		}
+		do {
+			FD_ZERO(&set);
+			FD_SET(sock, &set);
+			tv.tv_sec=0;
+			tv.tv_usec=0;
+			select(sock+1, &set, NULL, NULL, &tv);
+			if(FD_ISSET(sock, &set)) {
+				/* Okay, there's something ready for
+				 * reading here */
+				if(read_packet_check_header(sock, 1024, i)<0) {
+					retval=-1;
+					goto err_open;
+				}
+				printf("Requests(-): %d\n", --requests);
+			}
+		} while FD_ISSET(sock, &set);
+		/* Now wait until we can write again or until a second have
+		 * passed, whichever comes first*/
+		FD_ZERO(&set);
+		FD_SET(sock, &set);
+		tv.tv_sec=1;
+		tv.tv_usec=0;
+		do_write=select(sock+1,NULL,&set,NULL,&tv);
+		if(!do_write) printf("Select finished\n");
+		if(do_write<0) {
+			snprintf(errstr, errstr_len, "select: %s", strerror(errno));
+			retval=-1;
+			goto err_open;
+		}
+	}
+	/* Now empty the read buffer */
+	do {
+		FD_ZERO(&set);
+		FD_SET(sock, &set);
+		tv.tv_sec=0;
+		tv.tv_usec=0;
+		select(sock+1, &set, NULL, NULL, &tv);
+		if(FD_ISSET(sock, &set)) {
+			/* Okay, there's something ready for
+			 * reading here */
+			read_packet_check_header(sock, 1024, i);
+			printf("Requests(-): %d\n", --requests);
+		}
+	} while (requests);
+	if(gettimeofday(&stop, NULL)<0) {
+		retval=-1;
+		snprintf(errstr, errstr_len, "Could not measure end time: %s", strerror(errno));
+		goto err_open;
+	}
+	timespan=stop.tv_sec-start.tv_sec+(stop.tv_usec-start.tv_usec)/1000000;
+	speed=(int)(size/timespan);
+	if(speed>1024) {
+		speed>>=10;
+		speedchar[0]='K';
+	}
+	if(speed>1024) {
+		speed>>=10;
+		speedchar[0]='M';
+	}
+	if(speed>1024) {
+		speed>>=10;
+		speedchar[0]='G';
+	}
+	g_message("Throughput test complete. Took %.3f seconds to complete, %d%sB/s",timespan,speed,speedchar);
+
+err_open:
+	if(close_sock) {
+		close_connection(sock, CONNECTION_CLOSE_PROPERLY);
+	}
+err:
+	return retval;
+}
+
+int main(int argc, char**argv) {
+	gchar *hostname;
+	long int p;
+	int port;
+	int sock=0;
+
+	if(argc<3) {
+		g_message("Not enough arguments");
+		g_message("Usage: %s <hostname> <port>", argv[0]);
+		exit(EXIT_FAILURE);
+	}
+	logging();
+	hostname=g_strdup(argv[1]);
+	p=(strtol(argv[2], NULL, 0));
+	if(p==LONG_MIN||p==LONG_MAX) {
+		g_critical("Could not parse port number: %s", strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+	port=(int)p;
+
+	if(throughput_test(hostname, port, sock, FALSE, TRUE)<0) {
+		g_warning("Could not run throughput test: %s", errstr);
+		exit(EXIT_FAILURE);
+	}
+
+	return 0;
+}
only in patch2:
unchanged:
--- nbd-2.9.14.orig/.pc/01_ipv6_support.patch/simple_test
+++ nbd-2.9.14/.pc/01_ipv6_support.patch/simple_test
@@ -0,0 +1,88 @@
+#!/bin/sh
+# Yes, that's POSIX sh, not bash!
+
+tmpnam=`mktemp`
+
+# Create a one-meg device
+dd if=/dev/zero of=$tmpnam bs=1024 count=1024
+
+echo $1
+
+case $1 in
+	*/cmd)
+		# Test with export specified on command line
+		./nbd-server -C /dev/null -p `pwd`/nbd-server.pid 11111 $tmpnam &
+		# -p only works if nbd-server wasn't compiled with -DNOFORK or
+		# -DNODAEMON, which I sometimes do for testing and debugging.
+		PID=$!
+		sleep 1
+		./nbd-tester-client 127.0.0.1 11111
+		retval=$?
+	;;
+
+	*/cfg1)
+		# Test with export specified in config file
+		cat > nbd-server.conf <<EOF
+[generic]
+[export]
+	exportname = $tmpnam
+	port = 11111
+EOF
+		./nbd-server -C nbd-server.conf -p `pwd`/nbd-server.pid &
+		PID=$!
+		sleep 1
+		./nbd-tester-client 127.0.0.1 11111
+		retval=$?
+	;;
+	*/cfgmulti)
+		# Test with multiple exports specified in config file, and
+		# testing more options too
+		cat >nbd-server.conf <<EOF
+[generic]
+[export1]
+	exportname = $tmpnam
+	port = 11111
+	copyonwrite = true
+	listenaddr = 127.0.0.1
+[export2]
+	exportname = $tmpnam
+	port = 11112
+	readonly = true
+EOF
+		./nbd-server -C nbd-server.conf -p `pwd`/nbd-server.pid &
+		PID=$!
+		sleep 1
+		./nbd-tester-client localhost 11111
+		retval=$?
+		if [ $retval -ne 0 ]
+		then
+			if [ -f nbd-server.pid ]
+			then
+				kill `cat nbd-server.pid`
+				rm -f nbd-server.pid
+			else
+				kill $PID
+			fi
+			rm -f $tmpnam nbd-server.conf
+			exit $retval
+		fi
+		./nbd-tester-client localhost 11112
+		retval=$?
+	;;
+	*)
+		echo "E: unknown test $1"
+		exit 1
+	;;
+esac
+if [ -f nbd-server.pid ]
+then
+	kill `cat nbd-server.pid`
+	rm -f nbd-server.pid
+else
+	kill $PID
+fi
+if [ $retval -ne 0 ]
+then
+	exit $retval
+fi
+rm -f $tmpnam nbd-server.conf
only in patch2:
unchanged:
--- nbd-2.9.14.orig/.pc/01_ipv6_support.patch/nbd-client.c
+++ nbd-2.9.14/.pc/01_ipv6_support.patch/nbd-client.c
@@ -0,0 +1,378 @@
+/*
+ * Open connection for network block device
+ *
+ * Copyright 1997,1998 Pavel Machek, distribute under GPL
+ *  <pa...@atrey.karlin.mff.cuni.cz>
+ *
+ * Version 1.0 - 64bit issues should be fixed, now
+ * Version 1.1 - added bs (blocksize) option (Alexey Guzeev, a...@permonline.ru)
+ * Version 1.2 - I added new option '-d' to send the disconnect request
+ * Version 2.0 - Version synchronised with server
+ * Version 2.1 - Check for disconnection before INIT_PASSWD is received
+ * 	to make errormsg a bit more helpful in case the server can't
+ * 	open the exported file.
+ */
+
+#include "config.h"
+#include "lfs.h"
+
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <netinet/tcp.h>
+#include <netinet/in.h>		/* sockaddr_in, htons, in_addr */
+#include <netdb.h>		/* hostent, gethostby*, getservby* */
+#include <stdio.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <stdlib.h>
+#include <sys/mount.h>
+#include <sys/mman.h>
+#include <errno.h>
+
+#ifndef __GNUC__
+#error I need GCC to work
+#endif
+
+#include <linux/ioctl.h>
+#define MY_NAME "nbd_client"
+#include "cliserv.h"
+
+int check_conn(char* devname, int do_print) {
+	char buf[256];
+	char* p;
+	int fd;
+	int len;
+	if(!strncmp(devname, "/dev/", 5)) {
+		devname+=5;
+	}
+	if((p=strchr(devname, 'p'))) {
+		/* We can't do checks on partitions. */
+		*p='\0';
+	}
+	snprintf(buf, 256, "/sys/block/%s/pid", devname);
+	if((fd=open(buf, O_RDONLY))<0) {
+		if(errno==ENOENT) {
+			return 1;
+		} else {
+			return 2;
+		}
+	}
+	len=read(fd, buf, 256);
+	buf[len-1]='\0';
+	if(do_print) printf("%s\n", buf);
+	return 0;
+}
+
+int opennet(char *name, int port, int sdp) {
+	int sock;
+	struct sockaddr_in xaddrin;
+	int xaddrinlen = sizeof(xaddrin);
+	struct hostent *hostn;
+	int af;
+
+	hostn = gethostbyname(name);
+	if (!hostn)
+		err("Gethostname failed: %h\n");
+
+	af = AF_INET;
+	if(sdp) {
+#ifdef WITH_SDP
+		af = AF_INET_SDP;
+#else
+		err("Can't do SDP: I was not compiled with SDP support!");
+#endif
+	}
+	if ((sock = socket(af, SOCK_STREAM, IPPROTO_TCP)) < 0)
+		err("Socket failed: %m");
+
+	xaddrin.sin_family = af;
+	xaddrin.sin_port = htons(port);
+	xaddrin.sin_addr.s_addr = *((int *) hostn->h_addr);
+	if ((connect(sock, (struct sockaddr *) &xaddrin, xaddrinlen) < 0))
+		err("Connect: %m");
+
+	setmysockopt(sock);
+	return sock;
+}
+
+void negotiate(int sock, u64 *rsize64, u32 *flags) {
+	u64 magic, size64;
+	char buf[256] = "\0\0\0\0\0\0\0\0\0";
+
+	printf("Negotiation: ");
+	if (read(sock, buf, 8) < 0)
+		err("Failed/1: %m");
+	if (strlen(buf)==0)
+		err("Server closed connection");
+	if (strcmp(buf, INIT_PASSWD))
+		err("INIT_PASSWD bad");
+	printf(".");
+	if (read(sock, &magic, sizeof(magic)) < 0)
+		err("Failed/2: %m");
+	magic = ntohll(magic);
+	if (magic != cliserv_magic)
+		err("Not enough cliserv_magic");
+	printf(".");
+
+	if (read(sock, &size64, sizeof(size64)) < 0)
+		err("Failed/3: %m\n");
+	size64 = ntohll(size64);
+
+#ifdef NBD_SET_SIZE_BLOCKS
+	if ((size64>>10) > (~0UL >> 1)) {
+		printf("size = %luMB", (unsigned long)(size64>>20));
+		err("Exported device is too big for me. Get 64-bit machine :-(\n");
+	} else
+		printf("size = %luKB", (unsigned long)(size64>>10));
+#else
+	if (size64 > (~0UL >> 1)) {
+		printf("size = %luKB", (unsigned long)(size64>>10));
+		err("Exported device is too big. Get 64-bit machine or newer kernel :-(\n");
+	} else
+		printf("size = %lu", (unsigned long)(size64));
+#endif
+
+	if (read(sock, flags, sizeof(*flags)) < 0)
+		err("Failed/4: %m\n");
+	*flags = ntohl(*flags);
+
+	if (read(sock, &buf, 124) < 0)
+		err("Failed/5: %m\n");
+	printf("\n");
+
+	*rsize64 = size64;
+}
+
+void setsizes(int nbd, u64 size64, int blocksize, u32 flags) {
+	unsigned long size;
+	int read_only = (flags & NBD_FLAG_READ_ONLY) ? 1 : 0;
+
+#ifdef NBD_SET_SIZE_BLOCKS
+	if (size64/blocksize > (~0UL >> 1))
+		err("Device too large.\n");
+	else {
+		int er;
+		if (ioctl(nbd, NBD_SET_BLKSIZE, (unsigned long)blocksize) < 0)
+			err("Ioctl/1.1a failed: %m\n");
+		size = (unsigned long)(size64/blocksize);
+		if ((er = ioctl(nbd, NBD_SET_SIZE_BLOCKS, size)) < 0)
+			err("Ioctl/1.1b failed: %m\n");
+		fprintf(stderr, "bs=%d, sz=%lu\n", blocksize, size);
+	}
+#else
+	if (size64 > (~0UL >> 1)) {
+		err("Device too large.\n");
+	} else {
+		size = (unsigned long)size64;
+		if (ioctl(nbd, NBD_SET_SIZE, size) < 0)
+			err("Ioctl NBD_SET_SIZE failed: %m\n");
+	}
+#endif
+
+	ioctl(nbd, NBD_CLEAR_SOCK);
+
+	if (ioctl(nbd, BLKROSET, (unsigned long) &read_only) < 0)
+		err("Unable to set read-only attribute for device");
+}
+
+void set_timeout(int nbd, int timeout) {
+	if (timeout) {
+#ifdef NBD_SET_TIMEOUT
+		if (ioctl(nbd, NBD_SET_TIMEOUT, (unsigned long)timeout) < 0)
+			err("Ioctl NBD_SET_TIMEOUT failed: %m\n");
+		fprintf(stderr, "timeout=%d\n", timeout);
+#else
+		err("Ioctl NBD_SET_TIMEOUT cannot be called when compiled on a system that does not support it\n");
+#endif
+	}
+}
+
+void finish_sock(int sock, int nbd, int swap) {
+	if (ioctl(nbd, NBD_SET_SOCK, sock) < 0)
+		err("Ioctl NBD_SET_SOCK failed: %m\n");
+
+	if (swap)
+		mlockall(MCL_CURRENT | MCL_FUTURE);
+}
+
+int main(int argc, char *argv[]) {
+	int port, sock, nbd;
+	int blocksize=1024;
+	char *hostname, *nbddev;
+	int swap=0;
+	int cont=0;
+	int timeout=0;
+	int sdp=0;
+	int nofork=0;
+	u64 size64;
+	u32 flags;
+
+	logging();
+
+	if (argc < 3) {
+	errmsg:
+		fprintf(stderr, "nbd-client version %s\n", PACKAGE_VERSION);
+		fprintf(stderr, "Usage: nbd-client [bs=blocksize] [timeout=sec] host port nbd_device [-swap] [-persist] [-nofork]\n");
+		fprintf(stderr, "Or   : nbd-client -d nbd_device\n");
+		fprintf(stderr, "Or   : nbd-client -c nbd_device\n");
+		fprintf(stderr, "Default value for blocksize is 1024 (recommended for ethernet)\n");
+		fprintf(stderr, "Allowed values for blocksize are 512,1024,2048,4096\n"); /* will be checked in kernel :) */
+		fprintf(stderr, "Note, that kernel 2.4.2 and older ones do not work correctly with\n");
+		fprintf(stderr, "blocksizes other than 1024 without patches\n");
+		return 1;
+	}
+
+	++argv; --argc; /* skip programname */
+
+	if (strcmp(argv[0], "-d")==0) {
+		nbd = open(argv[1], O_RDWR);
+		if (nbd < 0)
+			err("Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
+		printf("Disconnecting: que, ");
+		if (ioctl(nbd, NBD_CLEAR_QUE)< 0)
+			err("Ioctl failed: %m\n");
+		printf("disconnect, ");
+#ifdef NBD_DISCONNECT
+		if (ioctl(nbd, NBD_DISCONNECT)<0)
+			err("Ioctl failed: %m\n");
+		printf("sock, ");
+#else
+		fprintf(stderr, "Can't disconnect: I was not compiled with disconnect support!\n" );
+		exit(1);
+#endif
+		if (ioctl(nbd, NBD_CLEAR_SOCK)<0)
+			err("Ioctl failed: %m\n");
+		printf("done\n");
+		return 0;
+	}
+	if(strcmp(argv[0], "-c")==0) {
+		return check_conn(argv[1], 1);
+	}
+	
+	if (strncmp(argv[0], "bs=", 3)==0) {
+		blocksize=atoi(argv[0]+3);
+		++argv; --argc; /* skip blocksize */
+	}
+
+	if (strncmp(argv[0], "timeout=", 8)==0) {
+		timeout=atoi(argv[0]+8);
+		++argv; --argc; /* skip timeout */
+	}
+	
+	if (argc==0) goto errmsg;
+	hostname=argv[0];
+	++argv; --argc; /* skip hostname */
+
+	if (argc==0) goto errmsg;
+	port = atoi(argv[0]);
+	++argv; --argc; /* skip port */
+
+	if (argc==0) goto errmsg;
+	nbddev = argv[0];
+	nbd = open(nbddev, O_RDWR);
+	if (nbd < 0)
+	  err("Cannot open NBD: %m\nPlease ensure the 'nbd' module is loaded.");
+	++argv; --argc; /* skip device */
+
+	if (argc>3) goto errmsg;
+	if (argc) {
+		if(strncmp(argv[0], "-swap", 5)==0) {
+			swap=1;
+			++argv;--argc;
+		}
+	}
+	if (argc) {
+		if(strncmp(argv[0], "-persist", 8)==0) {
+			cont=1;
+			++argv;--argc;
+		}
+	}
+	if (argc) {
+		if(strncmp(argv[0], "-sdp", 4)==0) {
+			sdp=1;
+			++argv;--argc;
+		}
+	}
+	if (argc) {
+		if(strncmp(argv[0], "-nofork", 7)==0) {
+			nofork=1;
+			++argv;--argc;
+		}
+	}
+	if(argc) goto errmsg;
+	sock = opennet(hostname, port, sdp);
+	argv=NULL; argc=0; /* don't use it later suddenly */
+
+	negotiate(sock, &size64, &flags);
+	setsizes(nbd, size64, blocksize, flags);
+	set_timeout(nbd, timeout);
+	finish_sock(sock, nbd, swap);
+
+	/* Go daemon */
+	
+#ifndef NOFORK
+	if(!nofork) daemon(0,0);
+	do {
+		if (fork()) {
+			/* Due to a race, the kernel NBD driver cannot
+			 * call for a reread of the partition table
+			 * in the handling of the NBD_DO_IT ioctl().
+			 * Therefore, this is done in the first open()
+			 * of the device. We therefore make sure that
+			 * the device is opened at least once after the
+			 * connection was made. This has to be done in a
+			 * separate process, since the NBD_DO_IT ioctl()
+			 * does not return until the NBD device has
+			 * disconnected.
+			 */
+			while(check_conn(nbddev, 0)) {
+				sleep(1);
+			}
+			open(nbddev, O_RDONLY);
+			exit(0);
+		}
+#endif
+
+		if (ioctl(nbd, NBD_DO_IT) < 0) {
+			fprintf(stderr, "Kernel call returned: %m");
+			if(errno==EBADR) {
+				/* The user probably did 'nbd-client -d' on us.
+				 * quit */
+				cont=0;
+			} else {
+				if(cont) {
+					u64 new_size;
+					u32 new_flags;
+
+					fprintf(stderr, " Reconnecting\n");
+					close(sock); close(nbd);
+					sock = opennet(hostname, port, sdp);
+					nbd = open(nbddev, O_RDWR);
+					negotiate(sock, &new_size, &new_flags);
+					if (size64 != new_size) {
+						err("Size of the device changed. Bye");
+					}
+					setsizes(nbd, size64, blocksize,
+								new_flags);
+
+					set_timeout(nbd, timeout);
+					finish_sock(sock,nbd,swap);
+				}
+			}
+		} else {
+			/* We're on 2.4. It's not clearly defined what exactly
+			 * happened at this point. Probably best to quit, now
+			 */
+			fprintf(stderr, "Kernel call returned.");
+			cont=0;
+		}
+	} while(cont);
+	printf("Closing: que, ");
+	ioctl(nbd, NBD_CLEAR_QUE);
+	printf("sock, ");
+	ioctl(nbd, NBD_CLEAR_SOCK);
+	printf("done\n");
+	return 0;
+}

Reply via email to