All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kinglong Mee <kinglongmee@gmail.com>
To: "J. Bruce Fields" <bfields@fieldses.org>
Cc: linux-nfs@vger.kernel.org, kinglongmee@gmail.com
Subject: [PATCH] NFS4.0: Add IPv6 support
Date: Sat, 17 May 2014 18:47:04 +0800	[thread overview]
Message-ID: <53773E28.5010206@gmail.com> (raw)

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


                 reply	other threads:[~2014-05-17 10:47 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=53773E28.5010206@gmail.com \
    --to=kinglongmee@gmail.com \
    --cc=bfields@fieldses.org \
    --cc=linux-nfs@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.