]> git.decadent.org.uk Git - nfs-utils.git/blobdiff - support/nfs/svc_socket.c
libexport.a: Refactor client_init()
[nfs-utils.git] / support / nfs / svc_socket.c
index ca323e6b9aa57c3251e854f5e98bf04b2c84d82a..f44217a404821dcd059e8374531d3ac32c12d1fa 100644 (file)
 #include <netdb.h>
 #include <rpc/rpc.h>
 #include <sys/socket.h>
+#include <sys/fcntl.h>
 #include <errno.h>
 
 #ifdef _LIBC
 # include <libintl.h>
 #else
-# include "config.h"
 # ifndef _
 #  define _(s)                 (s)
 # endif
@@ -35,7 +35,6 @@
 # define __close(f)            close ((f))
 #endif
 
-#if !defined HAVE_SVCTCP_SOCKET || !defined HAVE_SVCUDP_SOCKET
 static int
 svc_socket (u_long number, int type, int protocol, int reuse)
 {
@@ -43,7 +42,7 @@ svc_socket (u_long number, int type, int protocol, int reuse)
   socklen_t len = sizeof (struct sockaddr_in);
   char rpcdata [1024], servdata [1024];
   struct rpcent rpcbuf, *rpcp;
-  struct servent servbuf, *servp;
+  struct servent servbuf, *servp = NULL;
   int sock, ret;
   const char *proto = protocol == IPPROTO_TCP ? "tcp" : "udp";
 
@@ -65,7 +64,7 @@ svc_socket (u_long number, int type, int protocol, int reuse)
        }
     }
 
-  __bzero ((char *) &addr, sizeof (addr));
+  memset (&addr, 0, sizeof (addr));
   addr.sin_family = AF_INET;
 
   ret = getrpcbynumber_r (number, &rpcbuf, rpcdata, sizeof rpcdata,
@@ -102,8 +101,6 @@ svc_socket (u_long number, int type, int protocol, int reuse)
     }
   else
     {
-      if (bindresvport (sock, &addr))
-       {
          addr.sin_port = 0;
          if (bind (sock, (struct sockaddr *) &addr, len) < 0)
            {
@@ -111,14 +108,42 @@ svc_socket (u_long number, int type, int protocol, int reuse)
              (void) __close (sock);
              sock = -1;
            }
-       }
+    }
+
+  if (sock >= 0)
+    {
+           /* This socket might be shared among multiple processes
+            * if mountd is run multi-threaded.  So it is safest to
+            * make it non-blocking, else all threads might wake
+            * one will get the data, and the others will block
+            * indefinitely.
+            * In all cases, transaction on this socket are atomic
+            * (accept for TCP, packet-read and packet-write for UDP)
+            * so O_NONBLOCK will not confuse unprepared code causing
+            * it to corrupt messages.
+            * It generally safest to have O_NONBLOCK when doing an accept
+            * as if we get a RST after the SYN and before accept runs,
+            * we can block despite being told there was an acceptable
+            * connection.
+            */
+       int flags;
+       if ((flags = fcntl(sock, F_GETFL)) < 0)
+         {
+             perror (_("svc_socket: can't get socket flags"));
+             (void) __close (sock);
+             sock = -1;
+         }
+       else if (fcntl(sock, F_SETFL, flags|O_NONBLOCK) < 0)
+         {
+             perror (_("svc_socket: can't set socket flags"));
+             (void) __close (sock);
+             sock = -1;
+         }
     }
 
   return sock;
 }
-#endif
 
-#ifndef HAVE_SVCTCP_SOCKET
 /*
  * Create and bind a TCP socket based on program number
  */
@@ -127,18 +152,15 @@ svctcp_socket (u_long number, int reuse)
 {
   return svc_socket (number, SOCK_STREAM, IPPROTO_TCP, reuse);
 }
-#endif
 
-#ifndef HAVE_SVCUDP_SOCKET
 /*
  * Create and bind a UDP socket based on program number
  */
 int
 svcudp_socket (u_long number, int reuse)
 {
-  return svc_socket (number, SOCK_DGRAM, IPPROTO_UDP, reuse);
+  return svc_socket (number, SOCK_DGRAM, IPPROTO_UDP, 0);
 }
-#endif
 
 #ifdef TEST
 static int