summaryrefslogtreecommitdiffstats
path: root/contrib/amd/conf/transp/transp_sockets.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/amd/conf/transp/transp_sockets.c')
-rw-r--r--contrib/amd/conf/transp/transp_sockets.c295
1 files changed, 224 insertions, 71 deletions
diff --git a/contrib/amd/conf/transp/transp_sockets.c b/contrib/amd/conf/transp/transp_sockets.c
index 23ed3f7..025e1f3 100644
--- a/contrib/amd/conf/transp/transp_sockets.c
+++ b/contrib/amd/conf/transp/transp_sockets.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: transp_sockets.c,v 1.6.2.11 2004/01/06 03:15:20 ezk Exp $
+ * File: am-utils/conf/transp/transp_sockets.c
*
* Socket specific utilities.
* -Erez Zadok <ezk@cs.columbia.edu>
@@ -55,18 +54,67 @@
* find the IP address that can be used to connect to the local host
*/
void
-amu_get_myaddress(struct in_addr *iap)
+amu_get_myaddress(struct in_addr *iap, const char *preferred_localhost)
{
+ struct hostent *hp;
+ char dq[20];
+
+#ifdef DEBUG_off
+#error this code is old and probably not useful any longer.
+#error Erez, Jan 21, 2004.
struct sockaddr_in sin;
+ /*
+ * Most modern systems should use 127.0.0.1 as the localhost address over
+ * which you can do NFS mounts. In the past we found that some NFS
+ * clients may not allow mounts from localhost. So we used
+ * get_myaddress() and that seemed to work. Alas, on some other systems,
+ * get_myaddress() may return one of the interface addresses at random,
+ * and thus use a less efficient IP address than 127.0.0.1. The solution
+ * is to hard-code 127.0.0.1, but still check if get_myaddress() returns a
+ * different value and warn about it.
+ */
memset((char *) &sin, 0, sizeof(sin));
get_myaddress(&sin);
- iap->s_addr = sin.sin_addr.s_addr;
+ if (sin.sin_addr.s_addr != htonl(INADDR_LOOPBACK))
+ dlog("amu_get_myaddress: myaddress conflict (0x%x vs. 0x%lx)",
+ sin.sin_addr.s_addr, (u_long) htonl(INADDR_LOOPBACK));
+#endif /* DEBUG_off */
+
+ if (preferred_localhost == NULL)
+ goto out;
+
+ /* if specified preferred locahost, then try to use it */
+ hp = gethostbyname(preferred_localhost);
+ if (hp == NULL) {
+ /* XXX: if hstrerror()/h_errno aren't portable, then need to port the next statement */
+ plog(XLOG_ERROR, "Unable to resolve localhost_address \"%s\" (%s): using default",
+ preferred_localhost, hstrerror(h_errno));
+ goto out;
+ }
+ if (hp->h_addr_list == NULL) {
+ plog(XLOG_ERROR, "localhost_address \"%s\" has no IP addresses: using default",
+ preferred_localhost);
+ goto out;
+ }
+ if (hp->h_addr_list[1] != NULL) {
+ plog(XLOG_ERROR, "localhost_address \"%s\" has more than one IP addresses: using first",
+ preferred_localhost);
+ goto out;
+ }
+ memmove((voidp) &iap->s_addr, (voidp) hp->h_addr_list[0], sizeof(iap->s_addr));
+ plog(XLOG_INFO, "localhost_address \"%s\" requested, using %s",
+ preferred_localhost, inet_dquad(dq, sizeof(dq), iap->s_addr));
+ return;
+
+ out:
+ iap->s_addr = htonl(INADDR_LOOPBACK);
}
/*
* How to bind to reserved ports.
+ * Note: if *pp is non-null and is greater than 0, then *pp will not be modified.
*/
int
bind_resv_port(int so, u_short *pp)
@@ -78,16 +126,21 @@ bind_resv_port(int so, u_short *pp)
memset((voidp) &sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
- port = IPPORT_RESERVED;
-
- do {
- --port;
- sin.sin_port = htons(port);
+ if (pp && *pp > 0) {
+ sin.sin_port = htons(*pp);
rc = bind(so, (struct sockaddr *) &sin, sizeof(sin));
- } while (rc < 0 && (int) port > IPPORT_RESERVED / 2);
+ } else {
+ port = IPPORT_RESERVED;
- if (pp && rc == 0)
- *pp = port;
+ do {
+ --port;
+ sin.sin_port = htons(port);
+ rc = bind(so, (struct sockaddr *) &sin, sizeof(sin));
+ } while (rc < 0 && (int) port > IPPORT_RESERVED / 2);
+
+ if (pp && rc == 0)
+ *pp = port;
+ }
return rc;
}
@@ -161,9 +214,7 @@ get_mount_client(char *unused_host, struct sockaddr_in *sin, struct timeval *tv,
*sock = RPC_ANYSOCK;
return NULL;
}
-#ifdef DEBUG
dlog("get_mount_client: Using udp, port %d", sin->sin_port);
-#endif /* DEBUG */
return client;
}
@@ -175,7 +226,19 @@ struct sockaddr_in *
amu_svc_getcaller(SVCXPRT *xprt)
{
/* glibc 2.2 returns a sockaddr_storage ??? */
- return (struct sockaddr_in *)svc_getcaller(xprt);
+ return (struct sockaddr_in *) svc_getcaller(xprt);
+}
+
+
+/*
+ * register an RPC server
+ */
+int
+amu_svc_register(SVCXPRT *xprt, u_long prognum, u_long versnum,
+ void (*dispatch)(struct svc_req *rqstp, SVCXPRT *transp),
+ u_long protocol, struct netconfig *dummy)
+{
+ return svc_register(xprt, prognum, versnum, dispatch, protocol);
}
@@ -188,21 +251,28 @@ create_nfs_service(int *soNFSp, u_short *nfs_portp, SVCXPRT **nfs_xprtp, void (*
*soNFSp = socket(AF_INET, SOCK_DGRAM, 0);
- if (*soNFSp < 0 || bind_resv_port(*soNFSp, NULL) < 0) {
+ if (*soNFSp < 0 || bind_resv_port(*soNFSp, nfs_portp) < 0) {
plog(XLOG_FATAL, "Can't create privileged nfs port (socket)");
+ if (*soNFSp >= 0)
+ close(*soNFSp);
return 1;
}
if ((*nfs_xprtp = svcudp_create(*soNFSp)) == NULL) {
plog(XLOG_FATAL, "cannot create rpc/udp service");
+ close(*soNFSp);
return 2;
}
if ((*nfs_portp = (*nfs_xprtp)->xp_port) >= IPPORT_RESERVED) {
plog(XLOG_FATAL, "Can't create privileged nfs port");
+ svc_destroy(*nfs_xprtp);
+ close(*soNFSp);
return 1;
}
if (!svc_register(*nfs_xprtp, NFS_PROGRAM, NFS_VERSION, dispatch_fxn, 0)) {
plog(XLOG_FATAL, "unable to register (%ld, %ld, 0)",
(u_long) NFS_PROGRAM, (u_long) NFS_VERSION);
+ svc_destroy(*nfs_xprtp);
+ close(*soNFSp);
return 3;
}
@@ -214,7 +284,13 @@ create_nfs_service(int *soNFSp, u_short *nfs_portp, SVCXPRT **nfs_xprtp, void (*
* Create the amq service for amd (both TCP and UDP)
*/
int
-create_amq_service(int *udp_soAMQp, SVCXPRT **udp_amqpp, int *tcp_soAMQp, SVCXPRT **tcp_amqpp)
+create_amq_service(int *udp_soAMQp,
+ SVCXPRT **udp_amqpp,
+ struct netconfig **dummy1,
+ int *tcp_soAMQp,
+ SVCXPRT **tcp_amqpp,
+ struct netconfig **dummy2,
+ u_short preferred_amq_port)
{
/* first create TCP service */
if (tcp_soAMQp) {
@@ -224,11 +300,25 @@ create_amq_service(int *udp_soAMQp, SVCXPRT **udp_amqpp, int *tcp_soAMQp, SVCXPR
return 1;
}
+ /* next, bind to a specific (TCP) port if asked for */
+ if (preferred_amq_port > 0) {
+ /*
+ * Note: if &preferred_amq_port is non-null and is greater than 0,
+ * then the pointer will not be modified. We don't want it to be
+ * modified because it was passed down to create_amq_service as a
+ * non-pointer (a variable on the stack, not to be modified!)
+ */
+ if (bind_resv_port(*tcp_soAMQp, &preferred_amq_port) < 0) {
+ plog(XLOG_FATAL, "can't bind amq service to requested TCP port %d: %m)", preferred_amq_port);
+ return 1;
+ }
+ }
+
/* now create RPC service handle for amq */
if (tcp_amqpp &&
(*tcp_amqpp = svctcp_create(*tcp_soAMQp, AMQ_SIZE, AMQ_SIZE)) == NULL) {
plog(XLOG_FATAL, "cannot create tcp service for amq: soAMQp=%d", *tcp_soAMQp);
- return 2;
+ return 1;
}
#ifdef SVCSET_CONNMAXREC
@@ -240,7 +330,7 @@ create_amq_service(int *udp_soAMQp, SVCXPRT **udp_amqpp, int *tcp_soAMQp, SVCXPR
# ifndef RPC_MAXDATASIZE
# define RPC_MAXDATASIZE 9000
# endif /* not RPC_MAXDATASIZE */
- {
+ if (tcp_amqpp) {
int maxrec = RPC_MAXDATASIZE;
SVC_CONTROL(*tcp_amqpp, SVCSET_CONNMAXREC, &maxrec);
}
@@ -252,14 +342,26 @@ create_amq_service(int *udp_soAMQp, SVCXPRT **udp_amqpp, int *tcp_soAMQp, SVCXPR
*udp_soAMQp = socket(AF_INET, SOCK_DGRAM, 0);
if (*udp_soAMQp < 0) {
plog(XLOG_FATAL, "cannot create udp socket for amq service: %m");
- return 3;
+ return 1;
+ }
+
+ /* next, bind to a specific (UDP) port if asked for */
+ if (preferred_amq_port > 0) {
+ /*
+ * Note: see comment about using &preferred_amq_port above in this
+ * function.
+ */
+ if (bind_resv_port(*udp_soAMQp, &preferred_amq_port) < 0) {
+ plog(XLOG_FATAL, "can't bind amq service to requested UDP port %d: %m)", preferred_amq_port);
+ return 1;
+ }
}
/* now create RPC service handle for amq */
if (udp_amqpp &&
(*udp_amqpp = svcudp_bufcreate(*udp_soAMQp, AMQ_SIZE, AMQ_SIZE)) == NULL) {
plog(XLOG_FATAL, "cannot create udp service for amq: soAMQp=%d", *udp_soAMQp);
- return 4;
+ return 1;
}
}
@@ -268,34 +370,47 @@ create_amq_service(int *udp_soAMQp, SVCXPRT **udp_amqpp, int *tcp_soAMQp, SVCXPR
/*
- * Ping the portmapper on a remote system by calling the nullproc
+ * Check if the portmapper is running and reachable: 0==down, 1==up
*/
-enum clnt_stat
-pmap_ping(struct sockaddr_in *address)
+int check_pmap_up(char *host, struct sockaddr_in* sin)
{
CLIENT *client;
enum clnt_stat clnt_stat = RPC_TIMEDOUT; /* assume failure */
int socket = RPC_ANYSOCK;
struct timeval timeout;
- timeout.tv_sec = 3;
+ timeout.tv_sec = 2;
timeout.tv_usec = 0;
- address->sin_port = htons(PMAPPORT);
- client = clntudp_create(address, PMAPPROG, PMAPVERS, timeout, &socket);
- if (client != (CLIENT *) NULL) {
- clnt_stat = clnt_call(client,
- PMAPPROC_NULL,
- (XDRPROC_T_TYPE) xdr_void,
- NULL,
- (XDRPROC_T_TYPE) xdr_void,
- NULL,
- timeout);
- clnt_destroy(client);
+ sin->sin_port = htons(PMAPPORT);
+ client = clntudp_create(sin, PMAPPROG, PMAPVERS, timeout, &socket);
+
+ if (client == (CLIENT *) NULL) {
+ plog(XLOG_ERROR,
+ "check_pmap_up: cannot create connection to contact portmapper on host \"%s\"%s",
+ host, clnt_spcreateerror(""));
+ return 0;
}
+
+ timeout.tv_sec = 6;
+ /* Ping the portmapper on a remote system by calling the nullproc */
+ clnt_stat = clnt_call(client,
+ PMAPPROC_NULL,
+ (XDRPROC_T_TYPE) xdr_void,
+ NULL,
+ (XDRPROC_T_TYPE) xdr_void,
+ NULL,
+ timeout);
+ clnt_destroy(client);
close(socket);
- address->sin_port = 0;
+ sin->sin_port = 0;
- return clnt_stat;
+ if (clnt_stat == RPC_TIMEDOUT) {
+ plog(XLOG_ERROR,
+ "check_pmap_up: failed to contact portmapper on host \"%s\": %s",
+ host, clnt_sperrno(clnt_stat));
+ return 0;
+ }
+ return 1;
}
@@ -310,6 +425,7 @@ get_nfs_version(char *host, struct sockaddr_in *sin, u_long nfs_version, const c
enum clnt_stat clnt_stat;
struct timeval tv;
int sock;
+ char *errstr;
/*
* If not set or set wrong, then try from NFS_VERS_MAX on down. If
@@ -319,23 +435,15 @@ get_nfs_version(char *host, struct sockaddr_in *sin, u_long nfs_version, const c
nfs_version = NFS_VERS_MAX;
again = 1;
}
- tv.tv_sec = 3; /* retry every 3 seconds, but also timeout */
+ tv.tv_sec = 2; /* retry every 2 seconds, but also timeout */
tv.tv_usec = 0;
- /*
- * First check if remote portmapper is up (verify if remote host is up).
- */
- clnt_stat = pmap_ping(sin);
- if (clnt_stat == RPC_TIMEDOUT) {
- plog(XLOG_ERROR, "get_nfs_version: failed to contact portmapper on host \"%s\": %s", host, clnt_sperrno(clnt_stat));
- return 0;
- }
-
#ifdef HAVE_FS_NFS3
try_again:
#endif /* HAVE_FS_NFS3 */
sock = RPC_ANYSOCK;
+ errstr = NULL;
if (STREQ(proto, "tcp"))
clnt = clnttcp_create(sin, NFS_PROGRAM, nfs_version, &sock, 0, 0);
else if (STREQ(proto, "udp"))
@@ -343,45 +451,90 @@ try_again:
else
clnt = NULL;
- if (clnt == NULL) {
+ if (clnt != NULL) {
+ /* Try three times (6/2=3) to verify the CLIENT handle. */
+ tv.tv_sec = 6;
+ clnt_stat = clnt_call(clnt,
+ NFSPROC_NULL,
+ (XDRPROC_T_TYPE) xdr_void,
+ 0,
+ (XDRPROC_T_TYPE) xdr_void,
+ 0,
+ tv);
+
+ if (clnt_stat != RPC_SUCCESS)
+ errstr = clnt_sperrno(clnt_stat);
+
+ close(sock);
+ clnt_destroy(clnt);
+ } else {
#ifdef HAVE_CLNT_SPCREATEERROR
- plog(XLOG_INFO, "get_nfs_version NFS(%d,%s) failed for %s: %s",
- (int) nfs_version, proto, host, clnt_spcreateerror(""));
+ errstr = clnt_spcreateerror("");
#else /* not HAVE_CLNT_SPCREATEERROR */
- plog(XLOG_INFO, "get_nfs_version NFS(%d,%s) failed for %s",
- (int) nfs_version, proto, host);
+ errstr = "";
#endif /* not HAVE_CLNT_SPCREATEERROR */
- return 0;
}
- /* Try a couple times to verify the CLIENT handle. */
- tv.tv_sec = 6;
- clnt_stat = clnt_call(clnt,
- NFSPROC_NULL,
- (XDRPROC_T_TYPE) xdr_void,
- 0,
- (XDRPROC_T_TYPE) xdr_void,
- 0,
- tv);
- close(sock);
- clnt_destroy(clnt);
- if (clnt_stat != RPC_SUCCESS) {
+ if (errstr) {
+ plog(XLOG_INFO, "get_nfs_version NFS(%d,%s) failed for %s%s",
+ (int) nfs_version, proto, host, errstr);
if (again) {
#ifdef HAVE_FS_NFS3
if (nfs_version == NFS_VERSION3) {
- plog(XLOG_INFO, "get_nfs_version trying a lower version");
nfs_version = NFS_VERSION;
again = 0;
+ plog(XLOG_INFO, "get_nfs_version trying a lower version: NFS(%d,%s)", (int) nfs_version, proto);
}
goto try_again;
#endif /* HAVE_FS_NFS3 */
}
- plog(XLOG_INFO, "get_nfs_version NFS(%d,%s) failed for %s",
- (int) nfs_version, proto, host);
return 0;
}
- plog(XLOG_INFO, "get_nfs_version: returning (%d,%s) on host %s",
+ plog(XLOG_INFO, "get_nfs_version: returning NFS(%d,%s) on host %s",
(int) nfs_version, proto, host);
return nfs_version;
}
+
+
+#if defined(HAVE_FS_AUTOFS) && defined(AUTOFS_PROG)
+/*
+ * Register the autofs service for amd
+ */
+int
+register_autofs_service(char *autofs_conftype, void (*autofs_dispatch)(struct svc_req *rqstp, SVCXPRT *transp))
+{
+ int autofs_socket;
+ SVCXPRT *autofs_xprt = NULL;
+
+ autofs_socket = socket(AF_INET, SOCK_DGRAM, 0);
+
+ if (autofs_socket < 0 || bind_resv_port(autofs_socket, NULL) < 0) {
+ plog(XLOG_FATAL, "Can't create privileged autofs port (socket)");
+ return 1;
+ }
+ if ((autofs_xprt = svcudp_create(autofs_socket)) == NULL) {
+ plog(XLOG_FATAL, "Can't create autofs rpc/udp service");
+ return 2;
+ }
+ if (autofs_xprt->xp_port >= IPPORT_RESERVED) {
+ plog(XLOG_FATAL, "Can't create privileged autofs port");
+ return 1;
+ }
+ if (!svc_register(autofs_xprt, AUTOFS_PROG, AUTOFS_VERS, autofs_dispatch, 0)) {
+ plog(XLOG_FATAL, "unable to register (%ld, %ld, 0)",
+ (u_long) AUTOFS_PROG, (u_long) AUTOFS_VERS);
+ return 3;
+ }
+
+ return 0; /* all is well */
+}
+
+
+int
+unregister_autofs_service(char *autofs_conftype)
+{
+ svc_unregister(AUTOFS_PROG, AUTOFS_VERS);
+ return 0;
+}
+#endif /* HAVE_FS_AUTOFS && AUTOFS_PROG */
OpenPOWER on IntegriCloud