support/nfs/svc_socket.c: New.
authorhjl <hjl>
Thu, 12 Sep 2002 21:09:58 +0000 (21:09 +0000)
committerhjl <hjl>
Thu, 12 Sep 2002 21:09:58 +0000 (21:09 +0000)
support/nfs/svc_socket.c [new file with mode: 0644]

diff --git a/support/nfs/svc_socket.c b/support/nfs/svc_socket.c
new file mode 100644 (file)
index 0000000..ca323e6
--- /dev/null
@@ -0,0 +1,187 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <rpc/rpc.h>
+#include <sys/socket.h>
+#include <errno.h>
+
+#ifdef _LIBC
+# include <libintl.h>
+#else
+# include "config.h"
+# ifndef _
+#  define _(s)                 (s)
+# endif
+# define __socket(d, t, p)     socket ((d), (t), (p))
+# 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)
+{
+  struct sockaddr_in addr;
+  socklen_t len = sizeof (struct sockaddr_in);
+  char rpcdata [1024], servdata [1024];
+  struct rpcent rpcbuf, *rpcp;
+  struct servent servbuf, *servp;
+  int sock, ret;
+  const char *proto = protocol == IPPROTO_TCP ? "tcp" : "udp";
+
+  if ((sock = __socket (AF_INET, type, protocol)) < 0)
+    {
+      perror (_("svc_socket: socket creation problem"));
+      return sock;
+    }
+
+  if (reuse)
+    {
+      ret = 1;
+      ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &ret,
+                       sizeof (ret));
+      if (ret < 0)
+       {
+         perror (_("svc_socket: socket reuse problem"));
+         return ret;
+       }
+    }
+
+  __bzero ((char *) &addr, sizeof (addr));
+  addr.sin_family = AF_INET;
+
+  ret = getrpcbynumber_r (number, &rpcbuf, rpcdata, sizeof rpcdata,
+                         &rpcp);
+  if (ret == 0 && rpcp != NULL)
+    {
+      /* First try name.  */
+      ret = getservbyname_r (rpcp->r_name, proto, &servbuf, servdata,
+                            sizeof servdata, &servp);
+      if ((ret != 0 || servp == NULL) && rpcp->r_aliases)
+       {
+         const char **a;
+
+         /* Then we try aliases.  */
+         for (a = (const char **) rpcp->r_aliases; *a != NULL; a++) 
+           {
+             ret = getservbyname_r (*a, proto, &servbuf, servdata,
+                                    sizeof servdata, &servp);
+             if (ret == 0 && servp != NULL)
+               break;
+           }
+       }
+    }
+
+  if (ret == 0 && servp != NULL)
+    {
+      addr.sin_port = servp->s_port;
+      if (bind (sock, (struct sockaddr *) &addr, len) < 0)
+       {
+         perror (_("svc_socket: bind problem"));
+         (void) __close (sock);
+         sock = -1;
+       }
+    }
+  else
+    {
+      if (bindresvport (sock, &addr))
+       {
+         addr.sin_port = 0;
+         if (bind (sock, (struct sockaddr *) &addr, len) < 0)
+           {
+             perror (_("svc_socket: bind problem"));
+             (void) __close (sock);
+             sock = -1;
+           }
+       }
+    }
+
+  return sock;
+}
+#endif
+
+#ifndef HAVE_SVCTCP_SOCKET
+/*
+ * Create and bind a TCP socket based on program number
+ */
+int
+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);
+}
+#endif
+
+#ifdef TEST
+static int
+check (u_long number, u_short port, int protocol, int reuse)
+{
+  int socket;
+  int result;
+  struct sockaddr_in addr;
+  socklen_t len = sizeof (struct sockaddr_in);
+
+  if (protocol == IPPROTO_TCP)
+    socket = svctcp_socket (number, reuse);
+  else
+    socket = svcudp_socket (number, reuse);
+
+  if (socket < 0)
+    return 1;
+
+  result = getsockname (socket, (struct sockaddr *) &addr, &len);
+  if (result == 0)
+    {
+      if (port != 0 && ntohs (addr.sin_port) != port)
+       printf ("Program: %ld, expect port: %d, got: %d\n",
+               number, port, ntohs (addr.sin_port)); 
+      else
+       printf ("Program: %ld, port: %d\n",
+               number, ntohs (addr.sin_port)); 
+    }
+
+  close (socket);
+  return result;
+}
+
+int
+main (void)
+{
+  int result = 0;
+
+  result += check (100001, 0, IPPROTO_TCP, 0);
+  result += check (100001, 0, IPPROTO_UDP, 0);
+  result += check (100003, 2049, IPPROTO_TCP, 1);
+  result += check (100003, 2049, IPPROTO_UDP, 1);
+
+  return result;
+}
+#endif