IPV6: Add basic IPv6 support

This adds basic IPv6 support to libnfs.
Since libnfs currently only support PORTMAPPER protocol up to version 2
the IPv6 support only works if the server runs Both MOUNT and NFS protocols
on the same ports for IPv6 as for IPv4.

To get full IPv6 support we need to add support for PORTMAPPER version 3
and use it for discovery when using IPv6
libnfs-4.0.0-vitalif
Ronnie Sahlberg 2014-03-16 09:12:49 -07:00
parent 7058971155
commit 1c1e09ad51
1 changed files with 47 additions and 16 deletions

View File

@ -80,7 +80,6 @@
#include "win32_errnowrapper.h"
#endif
static int rpc_reconnect_requeue(struct rpc_context *rpc);
static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_storage *s);
@ -418,6 +417,15 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s
if (rpc->tcp_syncnt != RPC_PARAM_UNDEFINED) {
set_tcp_sockopt(rpc->fd, TCP_SYNCNT, rpc->tcp_syncnt);
}
#endif
break;
case AF_INET6:
socksize = sizeof(struct sockaddr_in6);
rpc->fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
#ifdef HAVE_NETINET_TCP_H
if (rpc->tcp_syncnt != RPC_PARAM_UNDEFINED) {
set_tcp_sockopt(rpc->fd, TCP_SYNCNT, rpc->tcp_syncnt);
}
#endif
break;
default:
@ -449,7 +457,7 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s
* binding will usually succeed.
*/
{
struct sockaddr_in sin;
struct sockaddr_storage ss;
static int portOfs = 0;
const int firstPort = 512; /* >= 512 according to Sun docs */
const int portCount = IPPORT_RESERVED - firstPort;
@ -466,12 +474,26 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s
/* skip well-known ports */
if (!getservbyport(port, "tcp")) {
memset(&sin, 0, sizeof(sin));
sin.sin_port = port;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = 0;
memset(&ss, 0, sizeof(ss));
rc = bind(rpc->fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in));
switch (s->ss_family) {
case AF_INET:
((struct sockaddr_in *)&ss)->sin_port = port;
((struct sockaddr_in *)&ss)->sin_family = AF_INET;
#ifdef HAVE_SOCKADDR_LEN
((struct sockaddr_in *)&ss)->sin_len = sizeof(struct sockaddr_in);
#endif
break;
case AF_INET6:
((struct sockaddr_in6 *)&ss)->sin6_port = port;
((struct sockaddr_in6 *)&ss)->sin6_family = AF_INET6;
#ifdef HAVE_SOCKADDR_LEN
((struct sockaddr_in6 *)&ss)->sin6_len = sizeof(struct sockaddr_in);
#endif
break;
}
rc = bind(rpc->fd, (struct sockaddr *)&ss, socksize);
#if !defined(WIN32)
/* we got EACCES, so don't try again */
if (rc != 0 && errno == EACCES)
@ -493,7 +515,7 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s
int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc_cb cb, void *private_data)
{
struct sockaddr_in *sin = (struct sockaddr_in *)&rpc->s;
struct addrinfo *ai = NULL;
assert(rpc->magic == RPC_CONTEXT_MAGIC);
@ -509,18 +531,25 @@ int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc
rpc->auto_reconnect = 0;
sin->sin_family = AF_INET;
sin->sin_port = htons(port);
if (inet_pton(AF_INET, server, &sin->sin_addr) != 1) {
rpc_set_error(rpc, "Not a valid server ip address");
if (getaddrinfo(server, NULL, NULL, &ai) != 0) {
rpc_set_error(rpc, "Invalid address:%s. "
"Can not resolv into IPv4/v6 structure.", server);
return -1;
}
}
switch (rpc->s.ss_family) {
switch (ai->ai_family) {
case AF_INET:
((struct sockaddr_in *)&rpc->s)->sin_family = ai->ai_family;
((struct sockaddr_in *)&rpc->s)->sin_port = htons(port);
#ifdef HAVE_SOCKADDR_LEN
sin->sin_len = sizeof(struct sockaddr_in);
((struct sockaddr_in *)&rpc->s)->sin_len = sizeof(struct sockaddr_in);
#endif
break;
case AF_INET6:
((struct sockaddr_in6 *)&rpc->s)->sin6_family = ai->ai_family;
((struct sockaddr_in6 *)&rpc->s)->sin6_port = htons(port);
#ifdef HAVE_SOCKADDR_LEN
((struct sockaddr_in6 *)&rpc->s)->sin6_len = sizeof(struct sockaddr_in6);
#endif
break;
}
@ -528,6 +557,8 @@ int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc
rpc->connect_cb = cb;
rpc->connect_data = private_data;
freeaddrinfo(ai);
if (rpc_connect_sockaddr_async(rpc, &rpc->s) != 0) {
return -1;
}