Manuel Menal's unfinished patch; Google Summer of Code 2006.


2006-07-03  Manuel Menal  <mmenal@hurdfr.org>

	* README: New file.

	* main.c (OPT_NFS_VERSION, OPT_MNT_TRANSP, OPT_NFS_TRANSP, 
	OPT_DEBUG): New option keys.
	(startup_options): Add --nfs-version, --mount-transport,
	--nfs-transport and --debug-file switches.
	(parse_startup_opt): Parse OPT_NFS_VERSION, OPT_MNT_TRANSP,
	OPT_NFS_TRANSP and OPT_DEBUG option keys. 

	* nfs.h: Renamed main_udp_socket to main_socket.
	* mount.c (mount_root): Likewise.
	* rpc.c (conduct_rpc, rpc_receive_thread): Likewise.
	* main.c (main): Move main socket creation...
	* mount.c (mount_root): ... here.
	* nfs.h (mount_transport, nfs_transport): New variables.
	* mount.c (mount_root): Use UDP or TCP for mount/NFS according to
	OPT_NFS_TRANSP and OPT_MNT_TRANSP.

	* nfs.h (read_lock): New variable.
	* main.c (read_lock): Initialize.
	(main): Lock read_lock at startup.
	* mount.c (mount_root): Lock/unlock when main_socket is
	connected/disconnected.
	* rpc.c (rpc_receive_thread): Lock/unlock before/after read().

	* mount.c (mount_root): Use mount_version instead of MOUNTVERS and
	protocol_version instead of NFS_VERSION.
	(mount_initialize_rpc): Likewise.
	* nfs.c (nfs_initialize_rpc): Likewise.
	* mount.h (MOUNTVERS): Removed macro.
	* nfs-spec.h (NFS_VERSION): Likewise.
	* nfs.h (xdr_encode_fhandle): Implement for NFSv3.
	(xdr_decode_fhandle): Likewise.

	* rpc.c (conduct_rpc): Return an error when the RPC was not entirely
	transmitted.
	(rpc_receive_thread): Skip 0-character read().

	* nfs.h (DEBUG): New macro.
	(debug): New variable.
	* main.c: Add debug statements.
	(main): Ignore SIGPIPE for debugging purposes.
	(main): Move netfs_init() call after the mount phase.
	(initial_transmit_timeout): Change from 1 to 10 seconds.
	* mount.c: Likewise.
	* nfs.c: Likewise.
	* ops.c: Likewise.

Index: nfs/README
===================================================================
RCS file: nfs/README
diff -N nfs/README
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ nfs/README	3 Jul 2006 20:52:58 -0000	1.1.2.1
@@ -0,0 +1,11 @@
+== Transport layer protocol ==
+
+The NFS protocol itself is supported on UDP only in NFSv2, and both in
+UDP and TCP starting from NFSv3.
+
+Thus,  specifiying the "transport_protocol"  argument will  change the
+transport protocol used for the portmapper and mount protocols.
+
+== Protocol versions ==
+
+NFSv2 works with mountv1 only. NFSv3 works with mountv3 only.
Index: nfs/main.c
===================================================================
RCS file: /cvsroot/hurd/hurd/nfs/main.c,v
retrieving revision 1.31
retrieving revision 1.31.4.1
diff -u -p -r1.31 -r1.31.4.1
--- nfs/main.c	13 May 2002 17:39:37 -0000	1.31
+++ nfs/main.c	3 Jul 2006 20:48:33 -0000	1.31.4.1
@@ -32,11 +32,23 @@
 #include <error.h>
 #include <version.h>
 
+#include <signal.h>
+
 char *netfs_server_name = "nfs";
 char *netfs_server_version = HURD_VERSION;
 
+int protocol_version = 2;
+int mount_version;
+
+struct protoent *nfs_transport = NULL;
+struct protoent *mount_transport = NULL;
+
+struct mutex read_lock = MUTEX_INITIALIZER;
+
 extern char *localhost ();
 
+FILE *debug = NULL;
+
 /* Default number of times to retry RPCs when mounted soft. */
 #define DEFAULT_SOFT_RETRIES  3
 
@@ -72,7 +84,7 @@ int name_cache_timeout = DEFAULT_NAME_CA
 int name_cache_neg_timeout = DEFAULT_NAME_CACHE_NEG_TIMEOUT;
 
 /* Number of seconds to wait for first retransmission of an RPC. */
-int initial_transmit_timeout = 1;
+int initial_transmit_timeout = 10;
 
 /* Maximum number of seconds to wait between retransmission of RPCs. */
 int max_transmit_timeout = 30;
@@ -93,6 +105,8 @@ int write_size = DEFAULT_WRITE_SIZE;
 #define OPT_HARD	'h'
 #define OPT_RSIZE	'R'
 #define OPT_WSIZE	'W'
+#define OPT_NFS_VERSION 'P'
+#define OPT_DEBUG       'd'
 #define OPT_STAT_TO	-2
 #define OPT_CACHE_TO	-3
 #define OPT_INIT_TR_TO	-4
@@ -107,6 +121,8 @@ int write_size = DEFAULT_WRITE_SIZE;
 #define OPT_PMAP_PORT	-13
 #define OPT_NCACHE_TO	-14
 #define OPT_NCACHE_NEG_TO -15
+#define OPT_MNT_TRANSP  -16
+#define OPT_NFS_TRANSP  -17
 
 /* Return a string corresponding to the printed rep of DEFAULT_what */
 #define ___D(what) #what
@@ -196,6 +212,12 @@ static const struct argp_option startup_
   {"nfs-program",           OPT_NFS_PROG,  "ID[.VERS]"},
 
   {"pmap-port",             OPT_PMAP_PORT,  "SVC|PORT"},
+  {"nfs-version",           OPT_NFS_VERSION, "VERSION"},
+  {"mount-transport",       OPT_MNT_TRANSP, "PROTOCOL", 0, 
+   "Transport protocol to use for mount and portmap (tcp ou udp)"},
+  {"nfs-transport",         OPT_NFS_TRANSP, "PROTOCOL", 0,
+   "Transport protocol to use for NFS (tcp or udp) (NFSv3 only)"},
+  {"debug-file", OPT_DEBUG, "FILE"},
 
   {"hold", OPT_HOLD, 0, OPTION_HIDDEN}, /*  */
   { 0 }
@@ -323,6 +345,43 @@ parse_startup_opt (int key, char *arg, s
       nfs_port = atoi (arg);
       break;
 
+    case OPT_NFS_VERSION: 
+      protocol_version = atoi (arg); 
+      break;
+
+    case OPT_MNT_TRANSP:
+      {
+	fprintf (stderr, "mount transport %s requested\n", arg);
+	struct protoent *proto = getprotobyname (arg);
+	if (proto == NULL)
+	  argp_error (state, "Invalid PROTOCOL specified");
+
+	mount_transport = malloc (sizeof (struct protoent));
+	mount_transport->p_proto = proto->p_proto;
+	mount_transport->p_name = strdup (proto->p_name);
+
+	fprintf (stderr, "mount transport %s saved\n", mount_transport->p_name);
+	break;
+      }
+
+    case OPT_NFS_TRANSP:
+      {
+	struct protoent *proto = getprotobyname (arg);
+	if (proto == NULL)
+	  argp_error (state, "Invalid PROTOCOL specified");
+
+	nfs_transport = malloc (sizeof (struct protoent));
+	nfs_transport->p_proto = proto->p_proto;
+	nfs_transport->p_name = strdup (proto->p_name);
+
+	break;
+      }
+
+    case OPT_DEBUG:
+      debug = fopen (arg, "w");
+      setbuf (debug, NULL);
+      break;
+
     case ARGP_KEY_ARG:
       if (state->arg_num == 0)
 	remote_fs = arg;
@@ -358,48 +417,85 @@ main (int argc, char **argv)
   struct argp argp =
     { startup_options, parse_startup_opt, args_doc, doc, argp_children };
   mach_port_t bootstrap;
-  struct sockaddr_in addr;
   int ret;
 
+  DEBUG("[%s] entering the NFS client : parsing command line\n", __PRETTY_FUNCTION__);
+
   argp_parse (&argp, argc, argv, 0, 0, 0);
-    
-  task_get_bootstrap_port (mach_task_self (), &bootstrap);
-  netfs_init ();
-  
-  main_udp_socket = socket (PF_INET, SOCK_DGRAM, 0);
-  addr.sin_family = AF_INET;
-  addr.sin_addr.s_addr = INADDR_ANY;
-  addr.sin_port = htons (IPPORT_RESERVED);
-  do
+
+  DEBUG("[%s] argument parsed, initializing socket and nodes\n", 
+	__PRETTY_FUNCTION__);
+
+  /* No  transport protocol  has been  specified  for nfs  : take  the
+     default one. */
+  if (!nfs_transport)
     {
-      addr.sin_port = htons (ntohs (addr.sin_port) - 1);
-      ret = bind (main_udp_socket, (struct sockaddr *)&addr, 
-		  sizeof (struct sockaddr_in));
-      if (ret == -1 && errno == EACCES)
-	{
-	  /* We aren't allowed privileged ports; no matter;
-	     let the server deny us later if it wants. */
-	  ret = 0;
-	  break;
-	}
+      DEBUG("[%s] no nfs transport provided, using default : %s\n", __PRETTY_FUNCTION__,
+	    DEFAULT_TRANSPORT_PROTOCOL);
+      struct protoent *proto = getprotobyname (DEFAULT_TRANSPORT_PROTOCOL);
+
+      nfs_transport = malloc (sizeof (struct protoent));
+      nfs_transport->p_proto = proto->p_proto;
+      nfs_transport->p_name = strdup (proto->p_name);
+    }
+  else
+    {
+      if (protocol_version == 2 
+	  && nfs_transport->p_proto != IPPROTO_UDP)
+	error (3, 0, "NFSv2 only supports UDP");
+    }
+
+  /* Same thing for mount/portmap. */
+  if (!mount_transport)
+    {
+      DEBUG("[%s] no mount transport provided, using default : %s\n", __PRETTY_FUNCTION__, DEFAULT_TRANSPORT_PROTOCOL);
+      struct protoent *proto = getprotobyname (DEFAULT_TRANSPORT_PROTOCOL);
+
+      mount_transport = malloc (sizeof (struct protoent));
+      mount_transport->p_proto = proto->p_proto;
+      mount_transport->p_name = strdup (proto->p_name);
     }
-  while ((ret == -1) && (errno == EADDRINUSE));
-  if (ret == -1)
-    error (1, errno, "binding main udp socket");
+
+  /* Each protocol version only supports one mount protocol version. */
+  switch (protocol_version)
+    {
+    case 2:
+      mount_version = 1;
+      break;
+    case 3:
+      mount_version = 3;
+      break;
+    default:
+      mount_version = 1;
+    }
+
+  DEBUG("[%s] NFS client running on NFSv%d,  using %s (%p) transport for NFS, %s (%p) for mount/portmap\n",
+	__PRETTY_FUNCTION__, protocol_version, nfs_transport->p_name, nfs_transport,
+	mount_transport->p_name, mount_transport);
+
+  task_get_bootstrap_port (mach_task_self (), &bootstrap);
 
   err = maptime_map (0, 0, &mapped_time);
+  
   if (err)
     error (2, err, "mapping time");
 
+  hostname = localhost ();
+
+  mutex_lock (&read_lock);
   cthread_detach (cthread_fork ((cthread_fn_t) timeout_service_thread, 0));
   cthread_detach (cthread_fork ((cthread_fn_t) rpc_receive_thread, 0));
-  
-  hostname = localhost ();
+
+  DEBUG("[%s] mounting root node\n", __PRETTY_FUNCTION__);
+
+  signal (SIGPIPE, SIG_IGN);
 
   netfs_root_node = mount_root (remote_fs, host);
 
   if (!netfs_root_node)
     exit (1);
+
+  netfs_init ();
   
   netfs_startup (bootstrap, 0);
   
Index: nfs/mount.c
===================================================================
RCS file: /cvsroot/hurd/hurd/nfs/mount.c,v
retrieving revision 1.27
retrieving revision 1.27.4.1
diff -u -p -r1.27 -r1.27.4.1
--- nfs/mount.c	29 Sep 2002 15:11:59 -0000	1.27
+++ nfs/mount.c	3 Jul 2006 20:48:33 -0000	1.27.4.1
@@ -35,6 +35,8 @@
 #include "nfs.h"
 #include "mount.h"
 
+int main_socket;
+
 /* Service name for portmapper */
 char *pmap_service_name = "sunrpc";
 
@@ -45,7 +47,7 @@ short pmap_service_number = PMAPPORT;
 int mount_program = MOUNTPROG;
 
 /* RPC version for mount server. */
-int mount_version = MOUNTVERS;
+int mount_version;
 
 /* Fallback port number for mount server. */
 short mount_port = 0;
@@ -56,9 +58,6 @@ int mount_port_override = 0;
 /* RPC program number for NFS server. */
 int nfs_program = NFS_PROGRAM;
 
-/* RPC version number for NFS server. */
-int nfs_version = NFS_VERSION;
-
 /* Fallback port number for NFS server. */
 short nfs_port = NFS_PORT;
 
@@ -69,7 +68,7 @@ int nfs_port_override = 0;
 const char *mounted_hostname;
 uint16_t mounted_nfs_port;	/* host order */
 
-int protocol_version = 2;
+FILE *debug;
 
 /* Set up an RPC for procedure PROCNUM for talking to the portmapper.
    Allocate storage with malloc and point *BUF at it; caller must free
@@ -88,7 +87,7 @@ pmap_initialize_rpc (int procnum, void *
 static int *
 mount_initialize_rpc (int procnum, void **buf)
 {
-  return initialize_rpc (MOUNTPROG, MOUNTVERS, procnum, 0, buf, 0, 0, -1);
+  return initialize_rpc (MOUNTPROG, mount_version, procnum, 0, buf, 0, 0, -1);
 }
 
 /* Using the mount protocol, lookup NAME at host HOST.
@@ -106,18 +105,49 @@ mount_root (char *name, char *host)
   struct node *np;
   short pmapport;
 
+  DEBUG("[%s] mounting share %s from host %s (using protocol version %d)\n", __PRETTY_FUNCTION__,
+	name, host, mount_version);
+
+  DEBUG("[%s] creating socket for mount %s\n", __PRETTY_FUNCTION__,
+	name, host);
+
+  error_t create_socket (int proto)
+  {
+    struct sockaddr_in addr;
+    int ret;
+
+    main_socket = socket (PF_INET,
+			  proto == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM, 0);
+    addr.sin_family = AF_INET;
+    addr.sin_addr.s_addr = INADDR_ANY;
+    addr.sin_port = htons (IPPORT_RESERVED);
+    do
+      {
+	addr.sin_port = htons (ntohs (addr.sin_port) - 1);
+	ret = bind (main_socket, (struct sockaddr *)&addr, 
+		    sizeof (struct sockaddr_in));
+	if (ret == -1 && errno == EACCES)
+	  {
+	    /* We aren't allowed privileged ports; no matter;
+	       let the server deny us later if it wants. */
+	    ret = 0;
+	    break;
+	  }
+      }
+    while ((ret == -1) && (errno == EADDRINUSE));
+
+    return ret;
+  }
+  
+  if (create_socket (mount_transport->p_proto))
+      error (1, errno, "binding main socket");
+
   /* Lookup the portmapper port number */
   if (pmap_service_name)
     {
       struct servent *s;
 
-      /* XXX This will always fail! pmap_service_name will always be "sunrpc"
-         What should pmap_service_name really be?  By definition the second
-	 argument is either "tcp" or "udp"  Thus, is this backwards
-	 (as service_name suggests)?  If so, should it read:
-             s = getservbyname (pmap_service_name, "udp");
-         or is there something I am missing here?  */
-      s = getservbyname ("sunrpc", pmap_service_name);
+      s = getservbyname (pmap_service_name, mount_transport->p_name);
       if (s)
 	pmapport = s->s_port;
       else
@@ -126,6 +156,9 @@ mount_root (char *name, char *host)
   else
     pmapport = htons (pmap_service_number);
 
+  DEBUG("[%s] got port %hd for portmapper\n", __PRETTY_FUNCTION__,
+	pmapport);
+
   /* Lookup the host */
   h = gethostbyname (host);
   if (!h)
@@ -142,15 +175,19 @@ mount_root (char *name, char *host)
     addr.sin_port = htons (mount_port);
   else
     {
+      DEBUG("[%s] getting the mount port via the portmapper\n", __PRETTY_FUNCTION__);
+
       /* Formulate and send a PMAPPROC_GETPORT request
 	 to lookup the mount program on the server.  */
-      if (connect (main_udp_socket, (struct sockaddr *)&addr,
+      if (connect (main_socket, (struct sockaddr *)&addr,
 	           sizeof (struct sockaddr_in)) == -1)
 	{
 	  error (0, errno, "server mount program");
 	  return 0;
 	}
 
+      mutex_unlock (&read_lock);
+
       p = pmap_initialize_rpc (PMAPPROC_GETPORT, &rpcbuf);
       if (! p)
 	{
@@ -158,9 +195,10 @@ mount_root (char *name, char *host)
 	  return 0;
 	}
 
+      DEBUG("[%s] conducting RPC\n", __PRETTY_FUNCTION__);
       *(p++) = htonl (MOUNTPROG);
-      *(p++) = htonl (MOUNTVERS);
-      *(p++) = htonl (IPPROTO_UDP);
+      *(p++) = htonl (mount_version);
+      *(p++) = htonl (mount_transport->p_proto);
       *(p++) = htonl (0);
       err = conduct_rpc (&rpcbuf, &p);
       if (!err)
@@ -173,21 +211,26 @@ mount_root (char *name, char *host)
 	addr.sin_port = htons (mount_port);
       else
 	{
+	  /* FIXME: Check with the other transport protocol (UDP/TCP) ? */
 	  error (0, err, "portmap of mount");
 	  goto error_with_rpcbuf;
 	}
       free (rpcbuf);
     }
 
+  DEBUG("[%s] connecting to the mount program\n", __PRETTY_FUNCTION__);
+
   /* Now, talking to the mount program, fetch a file handle
      for the root. */
-  if (connect (main_udp_socket, (struct sockaddr *) &addr,
+  if (connect (main_socket, (struct sockaddr *) &addr,
 	       sizeof (struct sockaddr_in)) == -1)
     {
       error (0, errno, "connect");
       goto error_with_rpcbuf;
     }
 
+  DEBUG("[%s] fetching root handle\n", __PRETTY_FUNCTION__);
+
   p = mount_initialize_rpc (MOUNTPROC_MNT, &rpcbuf);
   if (! p)
     {
@@ -195,6 +238,8 @@ mount_root (char *name, char *host)
       goto error_with_rpcbuf;
     }
 
+  DEBUG("[%s] MOUNTPROC initialized, conducting RPC\n", __PRETTY_FUNCTION__);
+
   p = xdr_encode_string (p, name);
   err = conduct_rpc (&rpcbuf, &p);
   if (err)
@@ -213,18 +258,27 @@ mount_root (char *name, char *host)
       goto error_with_rpcbuf;
     }
 
+  DEBUG("[%s] RPC returned, fetching the handle\n", __PRETTY_FUNCTION__);
+
   /* Create the node for root */
+
   xdr_decode_fhandle (p, &np);
+
+  DEBUG("[%s] retrieved handle, freeing rpcbuf\n", __PRETTY_FUNCTION__);
+
   free (rpcbuf);
   mutex_unlock (&np->lock);
 
+  DEBUG("[%s] retrieving port number for the NFS server\n", 
+	__PRETTY_FUNCTION__);
+
   if (nfs_port_override)
     port = nfs_port;
   else
     {
       /* Send another PMAPPROC_GETPORT request to lookup the nfs server. */
       addr.sin_port = pmapport;
-      if (connect (main_udp_socket, (struct sockaddr *) &addr,
+      if (connect (main_socket, (struct sockaddr *) &addr,
 	           sizeof (struct sockaddr_in)) == -1)
 	{
 	  error (0, errno, "connect");
@@ -238,8 +292,8 @@ mount_root (char *name, char *host)
 	  goto error_with_rpcbuf;
 	}
       *(p++) = htonl (NFS_PROGRAM);
-      *(p++) = htonl (NFS_VERSION);
-      *(p++) = htonl (IPPROTO_UDP);
+      *(p++) = htonl (protocol_version);
+      *(p++) = htonl (nfs_transport->p_proto);
       *(p++) = htonl (0);
       err = conduct_rpc (&rpcbuf, &p);
       if (!err)
@@ -257,8 +311,21 @@ mount_root (char *name, char *host)
       free (rpcbuf);
     }
 
+  if (nfs_transport->p_proto != mount_transport->p_proto)
+    {
+      mutex_lock (&read_lock);
+      /* Close the temporary socket. */
+      close (main_socket);
+
+      if (create_socket (nfs_transport->p_proto))
+	error (2, errno, "binding main nfs socket");
+      mutex_unlock (&read_lock);
+    }
+
+  DEBUG("[%s] connecting to NFS server on port %hd\n", 
+	__PRETTY_FUNCTION__, port);
   addr.sin_port = htons (port);
-  if (connect (main_udp_socket, (struct sockaddr *) &addr,
+  if (connect (main_socket, (struct sockaddr *) &addr,
 	       sizeof (struct sockaddr_in)) == -1)
     {
       error (0, errno, "connect");
Index: nfs/mount.h
===================================================================
RCS file: /cvsroot/hurd/hurd/nfs/mount.h,v
retrieving revision 1.5
retrieving revision 1.5.4.1
diff -u -p -r1.5 -r1.5.4.1
--- nfs/mount.h	30 Jan 2001 00:38:45 -0000	1.5
+++ nfs/mount.h	3 Jul 2006 20:48:33 -0000	1.5.4.1
@@ -24,7 +24,6 @@
 #define NFS_MOUNT_H
 
 #define MOUNTPROG 100005
-#define MOUNTVERS 1
 
 /* Obnoxious arbitrary limits */
 #define MOUNT_MNTPATHLEN 1024
Index: nfs/nfs-spec.h
===================================================================
RCS file: /cvsroot/hurd/hurd/nfs/nfs-spec.h,v
retrieving revision 1.2
retrieving revision 1.2.4.1
diff -u -p -r1.2 -r1.2.4.1
--- nfs/nfs-spec.h	30 Jan 2001 00:38:45 -0000	1.2
+++ nfs/nfs-spec.h	3 Jul 2006 20:48:33 -0000	1.2.4.1
@@ -101,7 +101,6 @@ enum createmode 
 };
 
 #define NFS_PROGRAM ((u_long)100003)
-#define NFS_VERSION ((u_long)2)
 
 #define NFS_PROTOCOL_FUNC(proc,vers) \
 	(vers == 2 ? NFS2PROC_ ## proc : NFS3PROC_ ## proc)
Index: nfs/nfs.c
===================================================================
RCS file: /cvsroot/hurd/hurd/nfs/nfs.c,v
retrieving revision 1.27
retrieving revision 1.27.4.1
diff -u -p -r1.27 -r1.27.4.1
--- nfs/nfs.c	29 Sep 2002 15:11:59 -0000	1.27
+++ nfs/nfs.c	3 Jul 2006 20:48:33 -0000	1.27.4.1
@@ -71,7 +71,7 @@ nfs_mode_to_hurd_mode (int type, int mod
 	    hurdmode = S_IFIFO;
 	    break;
 	  }
-      else
+      else if (protocol_version == 3)
 	switch (type)
 	  {
 	  case NF3FIFO:
@@ -143,6 +143,11 @@ xdr_encode_fhandle (int *p, struct fhand
       memcpy (p, fhandle->data, NFS2_FHSIZE);
       return p + INTSIZE (NFS2_FHSIZE);
     }
+  else if (protocol_version == 3)
+    {
+      memcpy (p, fhandle->data, NFS3_FHSIZE);
+      return p + INTSIZE (NFS3_FHSIZE);
+    }
   else
     return xdr_encode_data (p, fhandle->data, fhandle->size);
 }
@@ -153,6 +158,8 @@ xdr_encode_data (int *p, char *data, siz
 {
   int nints = INTSIZE (len);
 
+  DEBUG("[%s] encoding string %s (length: %d)\n",
+	__PRETTY_FUNCTION__, data, len);
   p[nints] = 0;
   *(p++) = htonl (len);
   memcpy (p, data, len);
@@ -384,13 +391,18 @@ xdr_decode_fhandle (int *p, struct node 
 
   if (protocol_version == 2)
     len = NFS2_FHSIZE;
+  else if (protocol_version == 3)
+    len = NFS3_FHSIZE;
   else
     {
       len = ntohl (*p);
       p++;
     }
+
+  DEBUG("[%s] looking up handle of length %d\n", __PRETTY_FUNCTION__, len);
   /* Enter into cache.  */
   lookup_fhandle (p, len, npp);
+  DEBUG("[%s] handle looked up\n", __PRETTY_FUNCTION__);
   return p + len / sizeof (int);
 }
 
@@ -575,7 +587,7 @@ nfs_initialize_rpc (int rpc_proc, struct
   else
     uid = gid = second_gid = -1;
 
-  return initialize_rpc (NFS_PROGRAM, NFS_VERSION, rpc_proc, len, bufp,
+  return initialize_rpc (NFS_PROGRAM, protocol_version, rpc_proc, len, bufp,
 			 uid, gid, second_gid);
 }
 
@@ -584,6 +596,9 @@ nfs_initialize_rpc (int rpc_proc, struct
 error_t
 nfs_error_trans (int error)
 {
+  DEBUG("[%s] translating NFS error code %d into Hurd error code\n",
+	__PRETTY_FUNCTION__, error);
+
   switch (error)
     {
     case NFS_OK:
Index: nfs/nfs.h
===================================================================
RCS file: /cvsroot/hurd/hurd/nfs/nfs.h,v
retrieving revision 1.18
retrieving revision 1.18.4.1
diff -u -p -r1.18 -r1.18.4.1
--- nfs/nfs.h	29 Dec 2001 00:40:09 -0000	1.18
+++ nfs/nfs.h	3 Jul 2006 20:48:33 -0000	1.18.4.1
@@ -24,6 +24,9 @@
 #include <sys/mman.h>
 #include "nfs-spec.h"
 #include <hurd/netfs.h>
+#include <netdb.h>
+
+#define DEFAULT_TRANSPORT_PROTOCOL "udp"
 
 /* A file handle */
 struct fhandle
@@ -77,7 +80,7 @@ struct netnode
 };
 
 /* Socket file descriptor for talking to RPC servers. */
-int main_udp_socket;
+int main_socket;
 
 /* Our hostname */
 char *hostname;
@@ -153,6 +156,17 @@ extern int nfs_port_override;
 /* Which NFS protocol version we are using */
 extern int protocol_version;
 
+/* Which transport protocol  (TCP or UDP) we are  using for portmapper
+   and mount. */
+extern struct protoent *mount_transport;
+
+/* Which transport protocol  (UDP for NFSv2, TCP or  UDP for NFSv3) we
+   are using for RPC.*/
+extern struct protoent *nfs_transport;
+
+/* Don't read on main_socket when this is locked. */
+extern struct mutex read_lock;
+
 
 /* Count how many four-byte chunks it takes to hold LEN bytes. */
 #define INTSIZE(len) (((len)+3)>>2)
@@ -200,4 +214,7 @@ void purge_lookup_cache (struct node *, 
 struct node *check_lookup_cache (struct node *, char *);
 void purge_lookup_cache_node (struct node *);
 
+extern FILE *debug;
+#define DEBUG(format, ...) if (debug) fprintf (debug, format, ## __VA_ARGS__)
+
 #endif /* NFS_NFS_H */
Index: nfs/ops.c
===================================================================
RCS file: /cvsroot/hurd/hurd/nfs/ops.c,v
retrieving revision 1.44
retrieving revision 1.44.4.1
diff -u -p -r1.44 -r1.44.4.1
--- nfs/ops.c	29 Sep 2002 15:11:59 -0000	1.44
+++ nfs/ops.c	3 Jul 2006 20:48:33 -0000	1.44.4.1
@@ -26,6 +26,8 @@
 #include <unistd.h>
 #include <maptime.h>
 
+FILE *debug;
+
 /* We have fresh stat information for NP; the file attribute (fattr)
    structure is at P.  Update our entry.  Return the address of the next
    int after the fattr structure.  */
@@ -34,6 +36,9 @@ register_fresh_stat (struct node *np, in
 {
   int *ret;
 
+  DEBUG ("[%s] registering retrieved attr into the node\n",
+	 __PRETTY_FUNCTION__);
+
   ret = xdr_decode_fattr (p, &np->nn_stat);
   np->nn->stat_updated = mapped_time->seconds;
 
@@ -143,26 +148,50 @@ netfs_validate_stat (struct node *np, st
   void *rpcbuf;
   error_t err;
 
+  DEBUG("[%s] validating stat for node %s\n", 
+	__PRETTY_FUNCTION__, "42");
+
   if (mapped_time->seconds - np->nn->stat_updated < stat_timeout)
     return 0;
 
   p = nfs_initialize_rpc (NFSPROC_GETATTR (protocol_version),
 			  (struct iouser *) -1, 0, &rpcbuf, np, -1);
+
+  DEBUG("[%s] RPC initialized (rpcbuf: %p)\n", __PRETTY_FUNCTION__,
+	rpcbuf);
   if (! p)
     return errno;
 
+  DEBUG("[%s] encoding file handle %s in XDR\n", 
+	__PRETTY_FUNCTION__, np->nn->handle.data);
+
   p = xdr_encode_fhandle (p, &np->nn->handle);
 
+  DEBUG("[%s] fhandle encoded (rpcbuf: %p)\n", 
+	__PRETTY_FUNCTION__, rpcbuf);
+
   err = conduct_rpc (&rpcbuf, &p);
   if (!err)
     {
+      DEBUG("[%s] error sending RPC : %d\n", __PRETTY_FUNCTION__,
+	    err);
       err = nfs_error_trans (ntohl (*p));
       p++;
     }
+
+  DEBUG("[%s] RPC sent (rpcbuf: %p)\n", __PRETTY_FUNCTION__,
+	rpcbuf);
+
   if (!err)
     register_fresh_stat (np, p);
 
+  DEBUG ("[%s] freeing rpcbuf (%p)\n", __PRETTY_FUNCTION__,
+	 rpcbuf);
+
   free (rpcbuf);
+
+  DEBUG("[%s] returning with error code %d\n", __PRETTY_FUNCTION__, 
+	err);
   return err;
 }
 
@@ -176,6 +205,8 @@ netfs_attempt_chown (struct iouser *cred
   void *rpcbuf;
   error_t err;
 
+  DEBUG("[%s] attempting chown\n", __PRETTY_FUNCTION__);
+
   p = nfs_initialize_rpc (NFSPROC_SETATTR (protocol_version),
 			  cred, 0, &rpcbuf, np, gid);
   if (! p)
@@ -392,6 +423,9 @@ netfs_attempt_statfs (struct iouser *cre
   void *rpcbuf;
   error_t err;
 
+  DEBUG("[%s] attempting statfs using node %s\n",
+	__PRETTY_FUNCTION__, "42");
+
   p = nfs_initialize_rpc (NFS2PROC_STATFS, cred, 0, &rpcbuf, np, -1);
   if (! p)
     return errno;
@@ -424,6 +458,10 @@ netfs_attempt_statfs (struct iouser *cre
     }
 
   free (rpcbuf);
+
+  DEBUG("[%s] returning with error code %d\n", 
+	__PRETTY_FUNCTION__, err);
+
   return err;
 }
 
@@ -457,6 +495,9 @@ netfs_attempt_read (struct iouser *cred,
   size_t amt, thisamt;
   int eof;
 
+  DEBUG("[%s] attempting to read %d bytes from node %s, starting from offset %d",
+	__PRETTY_FUNCTION__, *len, "42", offset);
+
   for (amt = *len; amt;)
     {
       thisamt = amt;
@@ -516,6 +557,9 @@ netfs_attempt_read (struct iouser *cred,
 	    }
 	}
     }
+
+  DEBUG("[%s] returning normally\n", __PRETTY_FUNCTION__);
+
   return 0;
 }
 
@@ -645,6 +689,9 @@ netfs_attempt_lookup (struct iouser *cre
   char dirhandle[NFS3_FHSIZE];
   size_t dirlen;
 
+  DEBUG("[%s] lookup for %s in directory %s\n",
+	__PRETTY_FUNCTION__, name, "42");
+
   /* Check the cache first. */
   *newnp = check_lookup_cache (np, name);
   if (*newnp)
@@ -673,10 +720,13 @@ netfs_attempt_lookup (struct iouser *cre
 
   mutex_unlock (&np->lock);
 
+  DEBUG("[%s] attempting lookup RPC (name: %s)\n", __PRETTY_FUNCTION__, name);
+
   err = conduct_rpc (&rpcbuf, &p);
   if (!err)
     {
       err = nfs_error_trans (ntohl (*p));
+      DEBUG("[%s] done, got error : %s (from %d : %d)\n", __PRETTY_FUNCTION__, strerror (err), ntohl (*p), *p);
       p++;
       if (!err)
 	{
@@ -704,6 +754,9 @@ netfs_attempt_lookup (struct iouser *cre
 
   free (rpcbuf);
 
+  DEBUG("[%s] returning with error code %d\n",
+	__PRETTY_FUNCTION__, err);
+
   return err;
 }
 
@@ -1430,6 +1483,9 @@ netfs_attempt_readlink (struct iouser *c
   void *rpcbuf;
   error_t err;
 
+  DEBUG("[%s] reading link %s\n", __PRETTY_FUNCTION__,
+	"42");
+
   if (np->nn->dtrans == SYMLINK)
     {
       strcpy (buf, np->nn->transarg.name);
@@ -1455,6 +1511,10 @@ netfs_attempt_readlink (struct iouser *c
     }
 
   free (rpcbuf);
+
+  DEBUG("[%s] returning with error code %d\n", __PRETTY_FUNCTION__,
+	err);
+
   return err;
 }
 
@@ -1466,10 +1526,16 @@ netfs_check_open_permissions (struct iou
 {
   int modes;
 
+  DEBUG("[%s] checking open permissions for node %s\n", 
+	__PRETTY_FUNCTION__, "42");
+
   if (newnode || (flags & (O_READ|O_WRITE|O_EXEC)) == 0)
     return 0;
 
   netfs_report_access (cred, np, &modes);
+
+  DEBUG("[%s] returning\n", __PRETTY_FUNCTION__);
+
   if ((flags & (O_READ|O_WRITE|O_EXEC)) == (flags & modes))
     return 0;
   else
@@ -1485,6 +1551,9 @@ netfs_report_access (struct iouser *cred
 {
   error_t err;
 
+  DEBUG("[%s] reporting access for node %s\n", __PRETTY_FUNCTION__,
+	"42");
+
   err = netfs_validate_stat (np, cred);
   if (err)
     return err;
@@ -1499,6 +1568,9 @@ netfs_report_access (struct iouser *cred
 	*types |= O_WRITE;
       if (fshelp_access (&np->nn_stat, S_IEXEC, cred) == 0)
 	*types |= O_EXEC;
+
+      DEBUG("[%s] returning with no problem\n", __PRETTY_FUNCTION__);
+
       return 0;
     }
   else
@@ -1544,6 +1616,10 @@ netfs_report_access (struct iouser *cred
 			| (ret & execute_check ? O_EXEC : 0));
 	    }
 	}
+
+      DEBUG("[%s] returning with error code %d\n", __PRETTY_FUNCTION__,
+	    err);
+
       return err;
     }
 }
Index: nfs/rpc.c
===================================================================
RCS file: /cvsroot/hurd/hurd/nfs/rpc.c,v
retrieving revision 1.12
retrieving revision 1.12.4.1
diff -u -p -r1.12 -r1.12.4.1
--- nfs/rpc.c	29 Sep 2002 15:11:59 -0000	1.12
+++ nfs/rpc.c	3 Jul 2006 20:48:33 -0000	1.12.4.1
@@ -44,6 +44,8 @@ struct rpc_list
   void *reply;
 };
 
+int main_socket;
+
 /* A list of all pending RPCs.  */
 static struct rpc_list *outstanding_rpcs;
 
@@ -86,6 +88,7 @@ initialize_rpc (int program, int version
   int *p, *lenaddr;
   struct rpc_list *hdr;
 
+  DEBUG("[%s] initializing RPC\n", __PRETTY_FUNCTION__);
   buf = malloc (len + 1024);
   if (! buf)
     {
@@ -99,6 +102,9 @@ initialize_rpc (int program, int version
   
   p = buf + sizeof (struct rpc_list);
 
+  DEBUG("[%s] filling the header : (xid, CALL, rpcver, program, version, rpcproc) = (xid, CALL, %d, %d, %d, %d)\n", 
+	__PRETTY_FUNCTION__, RPC_MSG_VERSION, program, version, rpc_proc);
+
   /* RPC header */
   *(p++) = htonl (generate_xid ());
   *(p++) = htonl (CALL);
@@ -106,7 +112,9 @@ initialize_rpc (int program, int version
   *(p++) = htonl (program);
   *(p++) = htonl (version);
   *(p++) = htonl (rpc_proc);
-  
+
+  DEBUG("[%s] filling the auth part of the header\n", __PRETTY_FUNCTION__);
+
   assert ((uid == -1) == (gid == -1));
 
   if (uid == -1)
@@ -135,7 +143,9 @@ initialize_rpc (int program, int version
 	}
       *lenaddr = htonl ((p - (lenaddr + 1)) * sizeof (int));
     }
-        
+
+  DEBUG("[%s] filling the VERF field\n", __PRETTY_FUNCTION__);
+
   /* VERF field */
   *(p++) = htonl (AUTH_NONE);
   *(p++) = 0;
@@ -186,6 +196,9 @@ conduct_rpc (void **rpcbuf, int **pp)
   int n;
   int cancel;
   
+  DEBUG("[%s] locking mutex to begin RPC\n", 
+	__PRETTY_FUNCTION__);
+
   mutex_lock (&outstanding_lock);
 
   link_rpc (&outstanding_rpcs, hdr);
@@ -202,27 +215,44 @@ conduct_rpc (void **rpcbuf, int **pp)
 	  return ETIMEDOUT;
 	}
 
+      DEBUG("[%s] issuing the RPC (try %d, previous at %d)\n", __PRETTY_FUNCTION__, 
+	    ntransmit, lasttrans);
       /* Issue the RPC.  */
       lasttrans = mapped_time->seconds;
       ntransmit++;
       nc = (void *) *pp - *rpcbuf - sizeof (struct rpc_list);
-      cc = write (main_udp_socket, *rpcbuf + sizeof (struct rpc_list), nc);
-      if (cc == -1)
+
+      DEBUG("[%s] writing to socket %d RPC of size %d, from %p\n", __PRETTY_FUNCTION__,
+	    main_socket, nc, *rpcbuf + sizeof (struct rpc_list));
+
+      cc = write (main_socket, *rpcbuf + sizeof (struct rpc_list), nc);
+
+      DEBUG("[%s] write returned %d\n", __PRETTY_FUNCTION__, cc);
+      if (cc != nc)
 	{
 	  unlink_rpc (hdr);
 	  mutex_unlock (&outstanding_lock);
 	  return errno;
 	}
-      else 
-	assert (cc == nc);
+      /*      else 
+	      assert (cc == nc);*/
       
+      DEBUG("[%s] issued, waiting for reply (timeout: %d seconds)\n", __PRETTY_FUNCTION__,
+	    timeout);
+
       /* Wait for reply.  */
       cancel = 0;
       while (!hdr->reply
 	     && (mapped_time->seconds - lasttrans < timeout)
 	     && !cancel)
-	cancel = hurd_condition_wait (&rpc_wakeup, &outstanding_lock);
+	{
+	  DEBUG("[%s] calling hurd_condition_wait\n", __PRETTY_FUNCTION__);
+	  cancel = hurd_condition_wait (&rpc_wakeup, &outstanding_lock);
+	}
   
+      DEBUG("[%s] wait ended: %s\n", __PRETTY_FUNCTION__,
+	    cancel ? "cancelled" : (hdr->reply ? "received reply" : "timeout exceeded"));
+
       if (cancel)
 	{
 	  unlink_rpc (hdr);
@@ -242,6 +272,8 @@ conduct_rpc (void **rpcbuf, int **pp)
     }
   while (!hdr->reply);
 
+  DEBUG("[%s] got reply, unlocking\n", __PRETTY_FUNCTION__);
+
   mutex_unlock (&outstanding_lock);
 
   /* Switch to the reply buffer.  */
@@ -256,22 +288,26 @@ conduct_rpc (void **rpcbuf, int **pp)
      something strange happened in rpc_receive_thread.  */
   assert (*p == xid);
   p++;
-  
+
   switch (ntohl (*p))
     {
     default:
+      DEBUG("[%s] unknown RPC encountered\n", __PRETTY_FUNCTION__);
       err = EBADRPC;
       break;
       
     case REPLY:
+      DEBUG("[%s] reply RPC, seeking status\n", __PRETTY_FUNCTION__);
       p++;
       switch (ntohl (*p))
 	{
 	default:
+	  DEBUG("[%s] unknown status\n", __PRETTY_FUNCTION__);
 	  err = EBADRPC;
 	  break;
 	  
 	case MSG_DENIED:
+	  DEBUG("[%s] got a permission denied RPC\n", __PRETTY_FUNCTION__);
 	  p++;
 	  switch (ntohl (*p))
 	    {
@@ -307,6 +343,7 @@ conduct_rpc (void **rpcbuf, int **pp)
 	  break;
 	  
 	case MSG_ACCEPTED:
+	  DEBUG("[%s] accepted status for RPC\n", __PRETTY_FUNCTION__);
 	  p++;
 
 	  /* Process VERF field.  */
@@ -335,8 +372,10 @@ conduct_rpc (void **rpcbuf, int **pp)
 	      break;
 
 	    case SUCCESS:
+	      DEBUG("[%s] RPC succeeded\n", __PRETTY_FUNCTION__);
 	      p++;
 	      *pp = p;
+	      DEBUG("[%s] status : %d\n", __PRETTY_FUNCTION__, ntohl(*p));
 	      err = 0;
 	      break;
 	    }
@@ -352,9 +391,13 @@ conduct_rpc (void **rpcbuf, int **pp)
 void
 timeout_service_thread ()
 {
+  DEBUG("[%s] creating timeout thread\n", __PRETTY_FUNCTION__);
+
   while (1)
     {
       sleep (1);
+      
+      DEBUG("[%s] *DING*\n", __PRETTY_FUNCTION__);
       mutex_lock (&outstanding_lock);
       condition_broadcast (&rpc_wakeup);
       mutex_unlock (&outstanding_lock);
@@ -368,30 +411,44 @@ rpc_receive_thread ()
 {
   void *buf;
 
+  DEBUG("[%s] creating receive thread\n", __PRETTY_FUNCTION__);
+
   /* Allocate a receive buffer.  */
   buf = malloc (1024 + read_size);
   assert (buf);
 
+  DEBUG("[%s] allocated read buffer of size %d (%p)\n", 
+	__PRETTY_FUNCTION__, 1024 + read_size, buf);
+
   while (1)
     {
-      int cc = read (main_udp_socket, buf, 1024 + read_size);
+      mutex_lock (&read_lock);
+      DEBUG("[%s] reading from RPC socket %d\n", __PRETTY_FUNCTION__, main_socket);
+      int cc = read (main_socket, buf, 1024 + read_size);
+      mutex_unlock (&read_lock);
       if (cc == -1)
         {
-          error (0, errno, "nfs read");
+	  DEBUG("[%s] reading failed : %s\n", __PRETTY_FUNCTION__, strerror (errno));
           continue;
         }
-      else
+      else if (cc > 0)
         {
           struct rpc_list *r;
           int xid = *(int *)buf;
 
+	  DEBUG("[%s] RPC received (%d bytes) : xid = %d, locking mutex\n", __PRETTY_FUNCTION__, 
+		cc, xid);
+
           mutex_lock (&outstanding_lock);
 
+	  DEBUG("[%s] mutex locked, finding out the original RPC\n", __PRETTY_FUNCTION__);
+
           /* Find the rpc that we just fulfilled.  */
           for (r = outstanding_rpcs; r; r = r->next)
     	    {
     	      if (* (int *) &r[1] == xid)
 	        {
+		  DEBUG("[%s] found the RPC which it replies to\n", __PRETTY_FUNCTION__);
 	          unlink_rpc (r);
 	          r->reply = buf;
 	          condition_broadcast (&rpc_wakeup);
@@ -409,8 +466,10 @@ rpc_receive_thread ()
 	     to get another request, a new buffer is needed.  */
 	  if (r)
 	    {
+	      DEBUG("[%s] allocating a new buffer\n", __PRETTY_FUNCTION__);
               buf = malloc (1024 + read_size);
               assert (buf);
+	      DEBUG("[%s] new buffer: %p\n", __PRETTY_FUNCTION__, buf);
 	    }
         }
     }
