transp_sockets.c revision 42629
1192886Sedwin/* 2192886Sedwin * Copyright (c) 1997-1998 Erez Zadok 32744Swollman * Copyright (c) 1990 Jan-Simon Pendry 458782Sru * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 558782Sru * Copyright (c) 1990 The Regents of the University of California. 658782Sru * All rights reserved. 7273718Sedwin * 843009Swollman * This code is derived from software contributed to Berkeley by 958782Sru * Jan-Simon Pendry at Imperial College, London. 10273718Sedwin * 1143009Swollman * Redistribution and use in source and binary forms, with or without 1219876Swollman * modification, are permitted provided that the following conditions 132744Swollman * are met: 14309583Sglebius * 1. Redistributions of source code must retain the above copyright 15309583Sglebius * notice, this list of conditions and the following disclaimer. 1658782Sru * 2. Redistributions in binary form must reproduce the above copyright 1758782Sru * notice, this list of conditions and the following disclaimer in the 18270728Spluknet * documentation and/or other materials provided with the distribution. 19270728Spluknet * 3. All advertising materials mentioning features or use of this software 20270728Spluknet * must display the following acknowledgment: 2158782Sru * This product includes software developed by the University of 22270728Spluknet * California, Berkeley and its contributors. 2358782Sru * 4. Neither the name of the University nor the names of its contributors 242744Swollman * may be used to endorse or promote products derived from this software 2519876Swollman * without specific prior written permission. 2630708Swollman * 2758782Sru * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2858782Sru * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29325324Sgordon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30309583Sglebius * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3158782Sru * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3219876Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3319876Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3458782Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3558782Sru * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3658782Sru * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3758782Sru * SUCH DAMAGE. 38199107Sedwin * 39199107Sedwin * %W% (Berkeley) %G% 40199107Sedwin * 41199107Sedwin * $Id: transp_sockets.c,v 1.2 1998/11/10 16:23:41 ezk Exp $ 42199107Sedwin * 43199107Sedwin * Socket specific utilities. 44199107Sedwin * -Erez Zadok <ezk@cs.columbia.edu> 45199107Sedwin */ 46199107Sedwin 47199107Sedwin#ifdef HAVE_CONFIG_H 48199107Sedwin# include <config.h> 49199107Sedwin#endif /* HAVE_CONFIG_H */ 50325324Sgordon#include <am_defs.h> 51199107Sedwin#include <amu.h> 52205475Sedwin 53249692Sedwin 54205475Sedwin/* 55205475Sedwin * find the IP address that can be used to connect to the local host 56205475Sedwin */ 57205475Sedwinvoid 58205475Sedwinamu_get_myaddress(struct in_addr *iap) 59205475Sedwin{ 60205475Sedwin struct sockaddr_in sin; 61205475Sedwin 62205475Sedwin memset((char *) &sin, 0, sizeof(sin)); 63205475Sedwin get_myaddress(&sin); 64205475Sedwin iap->s_addr = sin.sin_addr.s_addr; 65325324Sgordon} 66205475Sedwin 67309583Sglebius 68309583Sglebius/* 69309583Sglebius * How to bind to reserved ports. 70309583Sglebius */ 7119876Swollmanint 72309583Sglebiusbind_resv_port(int so, u_short *pp) 73309583Sglebius{ 74309583Sglebius struct sockaddr_in sin; 75309583Sglebius int rc; 76309583Sglebius u_short port; 77309583Sglebius 78309583Sglebius memset((voidp) &sin, 0, sizeof(sin)); 79309583Sglebius sin.sin_family = AF_INET; 80309583Sglebius 81309583Sglebius port = IPPORT_RESERVED; 82309583Sglebius 83309583Sglebius do { 84309583Sglebius --port; 85309583Sglebius sin.sin_port = htons(port); 86309583Sglebius rc = bind(so, (struct sockaddr *) &sin, sizeof(sin)); 87309583Sglebius } while (rc < 0 && (int) port > IPPORT_RESERVED / 2); 88309583Sglebius 89309583Sglebius if (pp && rc == 0) 9019876Swollman *pp = port; 9143009Swollman 92273718Sedwin return rc; 9343009Swollman} 94273718Sedwin 9543009Swollman 96273718Sedwin/* 9714338Swollman * close a descriptor, Sockets style 98270728Spluknet */ 99270728Spluknetint 100270728Spluknetamu_close(int fd) 10119876Swollman{ 102270728Spluknet return close(fd); 10314338Swollman} 104270728Spluknet 105270728Spluknet 106270728Spluknet/* 10786218Swollman * Create an rpc client attached to the mount daemon. 10858782Sru */ 109270728SpluknetCLIENT * 110270728Spluknetget_mount_client(char *unused_host, struct sockaddr_in *sin, struct timeval *tv, int *sock, u_long mnt_version) 111270728Spluknet{ 112149511Swollman CLIENT *client; 113325324Sgordon 114325324Sgordon /* 11514338Swollman * First try a TCP socket 11619876Swollman */ 117149511Swollman if ((*sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) > 0) { 118149511Swollman /* 11919876Swollman * Bind to a privileged port 120270728Spluknet */ 12119876Swollman if (bind_resv_port(*sock, (u_short *) 0) < 0) 122153667Swollman plog(XLOG_ERROR, "can't bind privileged port"); 123273718Sedwin 12430708Swollman /* 125270728Spluknet * Find mountd port to connect to. 126270728Spluknet * Connect to mountd. 12730708Swollman * Create a tcp client. 12830708Swollman */ 12919876Swollman if ((sin->sin_port = htons(pmap_getport(sin, MOUNTPROG, mnt_version, IPPROTO_TCP))) != 0) { 13019876Swollman if (connect(*sock, (struct sockaddr *) sin, sizeof(*sin)) >= 0 131270728Spluknet && ((client = clnttcp_create(sin, MOUNTPROG, mnt_version, sock, 0, 0)) != NULL)) 132270728Spluknet return client; 133270728Spluknet } 134270728Spluknet /* 135270728Spluknet * Failed so close socket 136270728Spluknet */ 13758782Sru (void) close(*sock); 13830708Swollman } /* tcp socket opened */ 13958782Sru /* TCP failed so try UDP */ 14058782Sru if ((*sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 14130708Swollman plog(XLOG_ERROR, "Can't create socket to connect to mountd: %m"); 14230708Swollman *sock = RPC_ANYSOCK; 143309583Sglebius return NULL; 144309583Sglebius } 14530708Swollman /* 14630708Swollman * Bind to a privileged port 147270728Spluknet */ 148325324Sgordon if (bind_resv_port(*sock, (u_short *) 0) < 0) 14930708Swollman plog(XLOG_ERROR, "can't bind privileged port"); 15030708Swollman 15130708Swollman /* 15230708Swollman * Zero out the port - make sure we recompute 15330708Swollman */ 154309583Sglebius sin->sin_port = 0; 155309583Sglebius 156309583Sglebius /* 157309583Sglebius * Make a UDP client 15819876Swollman */ 159270728Spluknet if ((client = clntudp_create(sin, MOUNTPROG, mnt_version, *tv, sock)) == NULL) { 160270728Spluknet (void) close(*sock); 161270728Spluknet *sock = RPC_ANYSOCK; 16219876Swollman return NULL; 163270728Spluknet } 16419876Swollman#ifdef DEBUG 165270728Spluknet dlog("get_mount_client: Using udp, port %d", sin->sin_port); 166270728Spluknet#endif /* DEBUG */ 167270728Spluknet return client; 16819876Swollman} 169270728Spluknet 170270728Spluknet 171270728Spluknet/* 17219876Swollman * find the address of the caller of an RPC procedure. 173270728Spluknet */ 17458782Srustruct sockaddr_in * 17558782Sruamu_svc_getcaller(SVCXPRT *xprt) 176153667Swollman{ 17758782Sru return svc_getcaller(xprt); 17858782Sru} 17958782Sru 18058782Sru 18158782Sru/* 182309583Sglebius * Bind NFS to a reserved port. 183309583Sglebius */ 18458782Srustatic int 18558782Srubindnfs_port(int so, u_short *nfs_portp) 186273718Sedwin{ 18719876Swollman u_short port; 18819876Swollman int error = bind_resv_port(so, &port); 189270728Spluknet 190149511Swollman if (error == 0) 19119876Swollman *nfs_portp = port; 19219876Swollman return error; 19330708Swollman} 19430708Swollman 19519876Swollman 19619876Swollman/* 197257681Sedwin * Create the nfs service for amd 198257681Sedwin */ 19919876Swollmanint 20019876Swollmancreate_nfs_service(int *soNFSp, u_short *nfs_portp, SVCXPRT **nfs_xprtp, void (*dispatch_fxn)(struct svc_req *rqstp, SVCXPRT *transp)) 20130708Swollman{ 20219876Swollman 20319876Swollman *soNFSp = socket(AF_INET, SOCK_DGRAM, 0); 20430708Swollman 205263901Sedwin if (*soNFSp < 0 || bindnfs_port(*soNFSp, nfs_portp) < 0) { 206263901Sedwin plog(XLOG_FATAL, "Can't create privileged nfs port"); 207263901Sedwin return 1; 208263901Sedwin } 209263901Sedwin if ((*nfs_xprtp = svcudp_create(*soNFSp)) == NULL) { 210263901Sedwin plog(XLOG_FATAL, "cannot create rpc/udp service"); 211263901Sedwin return 2; 212263901Sedwin } 213263901Sedwin if (!svc_register(*nfs_xprtp, NFS_PROGRAM, NFS_VERSION, dispatch_fxn, 0)) { 214263901Sedwin plog(XLOG_FATAL, "unable to register (NFS_PROGRAM, NFS_VERSION, 0)"); 215263901Sedwin return 3; 216263901Sedwin } 217263901Sedwin 218263901Sedwin return 0; /* all is well */ 219263901Sedwin} 220309583Sglebius 221263901Sedwin 222263901Sedwin/* 223263901Sedwin * Create the amq service for amd (both TCP and UDP) 224263901Sedwin */ 225309583Sglebiusint 226309583Sglebiuscreate_amq_service(int *udp_soAMQp, SVCXPRT **udp_amqpp, int *tcp_soAMQp, SVCXPRT **tcp_amqpp) 227309583Sglebius{ 228309583Sglebius /* first create TCP service */ 229263901Sedwin if (tcp_soAMQp) { 230309583Sglebius *tcp_soAMQp = socket(AF_INET, SOCK_STREAM, 0); 231263901Sedwin if (*tcp_soAMQp < 0) { 232309583Sglebius plog(XLOG_FATAL, "cannot create tcp socket for amq service: %m"); 233273718Sedwin return 1; 23419876Swollman } 23519876Swollman 23658782Sru /* now create RPC service handle for amq */ 23719876Swollman if (tcp_amqpp && 238270728Spluknet (*tcp_amqpp = svctcp_create(*tcp_soAMQp, AMQ_SIZE, AMQ_SIZE)) == NULL) { 239270728Spluknet plog(XLOG_FATAL, "cannot create tcp service for amq: soAMQp=%d", *tcp_soAMQp); 240270728Spluknet return 2; 24119876Swollman } 24258782Sru } 24358782Sru 244149511Swollman /* next create UDP service */ 245149511Swollman if (udp_soAMQp) { 24675264Swollman *udp_soAMQp = socket(AF_INET, SOCK_DGRAM, 0); 24775264Swollman if (*udp_soAMQp < 0) { 24819876Swollman plog(XLOG_FATAL, "cannot create udp socket for amq service: %m"); 24975264Swollman return 3; 250273718Sedwin } 251273718Sedwin 25275264Swollman /* now create RPC service handle for amq */ 25375264Swollman if (udp_amqpp && 25475264Swollman (*udp_amqpp = svcudp_bufcreate(*udp_soAMQp, AMQ_SIZE, AMQ_SIZE)) == NULL) { 25575264Swollman plog(XLOG_FATAL, "cannot create udp service for amq: soAMQp=%d", *udp_soAMQp); 25675264Swollman return 4; 25775264Swollman } 258257681Sedwin } 25975264Swollman 26075264Swollman return 0; /* all is well */ 26175264Swollman} 262257681Sedwin 26375264Swollman 26486218Swollman/* 26586218Swollman * Ping the portmapper on a remote system by calling the nullproc 266270728Spluknet */ 26786218Swollmanenum clnt_stat 26886218Swollmanpmap_ping(struct sockaddr_in *address) 26986218Swollman{ 27086218Swollman CLIENT *client; 271309583Sglebius enum clnt_stat clnt_stat = RPC_TIMEDOUT; /* assume failure */ 27286218Swollman int socket = RPC_ANYSOCK; 273309583Sglebius struct timeval timeout; 274309583Sglebius 27575264Swollman timeout.tv_sec = 3; 27619876Swollman timeout.tv_usec = 0; 277149511Swollman address->sin_port = htons(PMAPPORT); 278270728Spluknet client = clntudp_create(address, PMAPPROG, PMAPVERS, timeout, &socket); 27919876Swollman if (client != (CLIENT *) NULL) { 280270728Spluknet clnt_stat = clnt_call(client, 281270728Spluknet PMAPPROC_NULL, 282270728Spluknet (XDRPROC_T_TYPE) xdr_void, 283270728Spluknet NULL, 28419876Swollman (XDRPROC_T_TYPE) xdr_void, 28519876Swollman NULL, 28619876Swollman timeout); 28730708Swollman clnt_destroy(client); 28858782Sru } 28919876Swollman close(socket); 29019876Swollman address->sin_port = 0; 29119876Swollman 29258782Sru return clnt_stat; 29375264Swollman} 29475264Swollman 29575264Swollman 29675264Swollman/* 29775264Swollman * Find the best NFS version for a host and protocol. 29875264Swollman */ 29975264Swollmanu_long 30019876Swollmanget_nfs_version(char *host, struct sockaddr_in *sin, u_long nfs_version, const char *proto) 301114170Swollman{ 302114170Swollman CLIENT *clnt; 303114170Swollman int again = 0; 304114170Swollman enum clnt_stat clnt_stat; 305114170Swollman struct timeval tv; 306309583Sglebius int sock; 307309583Sglebius 30819876Swollman /* 30919876Swollman * If not set or set wrong, then try from NFS_VERS_MAX on down. If 31058782Sru * set, then try from nfs_version on down. 31119876Swollman */ 31219876Swollman if (nfs_version <= 0 || nfs_version > NFS_VERS_MAX) { 31319876Swollman nfs_version = NFS_VERS_MAX; 31420091Swollman again = 1; 315283042Sedwin } 31619876Swollman tv.tv_sec = 3; /* retry every 3 seconds, but also timeout */ 317257681Sedwin tv.tv_usec = 0; 318257681Sedwin 31919876Swollman /* 320153667Swollman * First check if remote portmapper is up (verify if remote host is up). 32119876Swollman */ 32219876Swollman clnt_stat = pmap_ping(sin); 32319876Swollman if (clnt_stat == RPC_TIMEDOUT) { 32419876Swollman plog(XLOG_ERROR, "get_nfs_version: failed to contact portmapper on host \"%s\": %s", host, clnt_sperrno(clnt_stat)); 32519876Swollman return 0; 326270728Spluknet } 32719876Swollman 32843009Swollman#ifdef HAVE_FS_NFS3 32943009Swollmantry_again: 33043009Swollman#endif /* HAVE_FS_NFS3 */ 33143009Swollman 33219876Swollman sock = RPC_ANYSOCK; 33319876Swollman if (STREQ(proto, "tcp")) 33419876Swollman clnt = clnttcp_create(sin, NFS_PROGRAM, nfs_version, &sock, 0, 0); 33519876Swollman else if (STREQ(proto, "udp")) 33619876Swollman clnt = clntudp_create(sin, NFS_PROGRAM, nfs_version, tv, &sock); 33719876Swollman else 33819876Swollman clnt = NULL; 33919876Swollman 340257681Sedwin if (clnt == NULL) { 341#ifdef HAVE_CLNT_SPCREATEERROR 342 plog(XLOG_INFO, "get_nfs_version NFS(%d,%s) failed for %s :%s", 343 nfs_version, proto, host, clnt_spcreateerror("")); 344#else /* not HAVE_CLNT_SPCREATEERROR */ 345 plog(XLOG_INFO, "get_nfs_version NFS(%d,%s) failed for %s", 346 nfs_version, proto, host); 347#endif /* not HAVE_CLNT_SPCREATEERROR */ 348 return 0; 349 } 350 351 /* Try a couple times to verify the CLIENT handle. */ 352 tv.tv_sec = 6; 353 clnt_stat = clnt_call(clnt, 354 NFSPROC_NULL, 355 (XDRPROC_T_TYPE) xdr_void, 356 0, 357 (XDRPROC_T_TYPE) xdr_void, 358 0, 359 tv); 360 close(sock); 361 clnt_destroy(clnt); 362 if (clnt_stat != RPC_SUCCESS) { 363 if (again) { 364#ifdef HAVE_FS_NFS3 365 if (nfs_version == NFS_VERSION3) { 366 plog(XLOG_INFO, "get_nfs_version trying a lower version"); 367 nfs_version = NFS_VERSION; 368 again = 0; 369 } 370 goto try_again; 371#endif /* HAVE_FS_NFS3 */ 372 } 373 plog(XLOG_INFO, "get_nfs_version NFS(%d,%s) failed for %s", 374 nfs_version, proto, host); 375 return 0; 376 } 377 378 plog(XLOG_INFO, "get_nfs_version: returning (%d,%s) on host %s", 379 nfs_version, proto, host); 380 return nfs_version; 381} 382 383 384/* 385 * AUTOFS FUNCTIONS FOR SOCKETS: 386 */ 387#ifdef HAVE_FS_AUTOFS 388/* 389 * Create the nfs service for amd 390 */ 391int 392create_autofs_service(int *soAUTOFSp, u_short *autofs_portp, SVCXPRT **autofs_xprtp, void (*dispatch_fxn)(struct svc_req *rqstp, SVCXPRT *transp)) 393{ 394 /* NOT IMPLEMENTED! */ 395 return -1; 396} 397#endif /* HAVE_FS_AUTOFS */ 398