All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] NFS4.0: Add IPv6 support
@ 2014-05-17 10:47 Kinglong Mee
  0 siblings, 0 replies; only message in thread
From: Kinglong Mee @ 2014-05-17 10:47 UTC (permalink / raw)
  To: J. Bruce Fields; +Cc: linux-nfs, kinglongmee

Signed-off-by: Kinglong Mee <kinglongmee@gmail.com>
---
 nfs4.0/lib/rpc/rpc.py | 15 ++++++++-----
 nfs4.0/nfs4lib.py     | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++
 nfs4.0/testserver.py  | 26 +++++-----------------
 3 files changed, 77 insertions(+), 25 deletions(-)

diff --git a/nfs4.0/lib/rpc/rpc.py b/nfs4.0/lib/rpc/rpc.py
index 60f70bd..8b39df4 100644
--- a/nfs4.0/lib/rpc/rpc.py
+++ b/nfs4.0/lib/rpc/rpc.py
@@ -188,6 +188,9 @@ class RPCClient(object):
         self.debug = 0
         t = threading.currentThread()
         self.lock = threading.Lock()
+        self.af = socket.AF_INET;
+        if host.find(':') != -1:
+            self.af = socket.AF_INET6;
         self.remotehost = host
         self.remoteport = port
         self.timeout = timeout
@@ -207,6 +210,7 @@ class RPCClient(object):
         self._init_security(self.sec_list) # Note this can make calls
         self.security = sec_list[0]
 
+
     def _init_security(self, list):
         # Each element of list must have functions:
         # initialize, secure_data, make_cred, make_verf
@@ -235,8 +239,7 @@ class RPCClient(object):
         if t in self._socket:
             out = self._socket[t]
         else:
-            out = self._socket[t] = socket.socket(socket.AF_INET,
-                                                  socket.SOCK_STREAM)
+            out = self._socket[t] = socket.socket(self.af, socket.SOCK_STREAM)
             if self.uselowport:
                 self.bindsocket(out)
             out.connect((self.remotehost, self.remoteport))
@@ -301,8 +304,7 @@ class RPCClient(object):
         t = threading.currentThread()
         self.lock.acquire()
         self._socket[t].close()
-        out = self._socket[t] = socket.socket(socket.AF_INET,
-                                              socket.SOCK_STREAM)
+        out = self._socket[t] = socket.socket(self.af, socket.SOCK_STREAM)
         # out.bind
         out.connect((self.remotehost, self.remoteport))
         out.settimeout(self.timeout)
@@ -454,7 +456,10 @@ class RPCClient(object):
 
 class Server(object):
     def __init__(self, host='', port=51423, name="SERVER"):
-        self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        try:
+            self.s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
+        except:
+            self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
         self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
         self.s.bind((host, port))
         self.port = self.s.getsockname()[1]
diff --git a/nfs4.0/nfs4lib.py b/nfs4.0/nfs4lib.py
index 5fc7bf3..994e0e1 100644
--- a/nfs4.0/nfs4lib.py
+++ b/nfs4.0/nfs4lib.py
@@ -39,6 +39,7 @@ import time
 import struct
 import socket
 import sys
+import re
 
 class NFSException(rpc.RPCError):
     pass
@@ -1013,4 +1014,64 @@ def bitmap2list(bitmap):
         bitmap >>= 1
     return out
 
+def path_components(path, use_dots=True):
+    """Convert a string '/a/b/c' into an array ['a', 'b', 'c']"""
+    out = []
+    for c in path.split('/'):
+        if c == '':
+            pass
+        elif use_dots and c == '.':
+            pass
+        elif use_dots and c == '..':
+            del out[-1]
+
+def parse_nfs_url(url):
+    """Parse [nfs://]host:port/path, format taken from rfc 2224
+       multipath addr:port pair are as such:
+
+      $ip1:$port1,$ip2:$port2..
+
+    Returns triple server, port, path.
+    """
+    p = re.compile(r"""
+    (?:nfs://)?               # Ignore an optionally prepended 'nfs://'
+    (?P<servers>[^/]+)
+    (?P<path>/.*)?            # set path=everything else, must start with /
+    $
+    """, re.VERBOSE)
+
+    m = p.match(url)
+    if m:
+        servers = m.group('servers')
+        server_list = []
+
+        for server in servers.split(','):
+            server = server.strip()
+
+            idx = server.rfind(':')
+            bracket_idx = server.rfind(']')
+
+            # the first : is before ipv6 addr ] -> no port specified
+            if bracket_idx > idx:
+                idx = -1
+
+            if idx >= 0:
+                host = server[:idx]
+                port = server[idx+1:]
+            else:
+                host = server
+                port = None
+
+            # remove brackets around IPv6 addrs, if they exist
+            if host.startswith('[') and host.endswith(']'):
+                host = host[1:-1]
+
+            port = (2049 if not port else int(port))
+            server_list.append((host, port))
 
+        path = m.group('path')
+        path = (path_components(path) if path else [])
+
+        return tuple(server_list), path
+    else:
+        raise ValueError("Error parsing NFS URL: %s" % url)
diff --git a/nfs4.0/testserver.py b/nfs4.0/testserver.py
index 606e2f0..41be74a 100755
--- a/nfs4.0/testserver.py
+++ b/nfs4.0/testserver.py
@@ -35,7 +35,6 @@ if  __name__ == "__main__":
     if os.path.isfile(os.path.join(sys.path[0], 'lib', 'testmod.py')):
         sys.path.insert(1, os.path.join(sys.path[0], 'lib'))
 
-import re
 import nfs4lib
 import testmod
 from optparse import OptionParser, OptionGroup, IndentedHelpFormatter
@@ -57,23 +56,6 @@ if not hasattr(os, "getgid"):
 else:
     GID = os.getgid()
 
-
-def parse_url(url):
-    """Parse [nfs://]host:port/path"""
-    p = re.compile(r"""
-    (?:nfs://)?      # Ignore an optionally prepended 'nfs://'
-    (?P<host>[^:]+)  # set host=everything up to next :
-    :?
-    (?P<port>[^/]*)  # set port=everything up to next /
-    (?P<path>/.*$|$) # set path=everything else
-    """, re.VERBOSE)
-
-    m = p.match(url)
-    if m:
-        return m.group('host'), m.group('port'), m.group('path')
-    else:
-        return None, None, None
-        
 def unixpath2comps(str, pathcomps=None):
     if pathcomps is None or str[0] == '/':
         pathcomps = []
@@ -284,9 +266,13 @@ def main():
     if not args:
         p.error("Need a server")
     url = args.pop(0)
-    opt.server, opt.port, opt.path = parse_url(url)
-    if not opt.server:
+    server_list, opt.path = nfs4lib.parse_nfs_url(url)
+
+    if not server_list:
         p.error("%s not a valid server name" % url)
+
+    opt.server, opt.port = server_list[0]
+
     if not opt.port:
         opt.port = 2049
     else:
-- 
1.9.0


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2014-05-17 10:47 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-05-17 10:47 [PATCH] NFS4.0: Add IPv6 support Kinglong Mee

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.