FreeBSD/sys/nlm/nlm_prot_impl.c
/*
 * Create an RPC client handle for the given (address,prog,vers)
 * triple using UDP.
 */
Create an RPC client handle for the given (address,prog,vers)
triple using UDP.
Create an RPC client handle for the given ( address prog vers ) triple using UDP .
static CLIENT *
nlm_get_rpc(struct sockaddr *sa, rpcprog_t prog, rpcvers_t vers)
{
	char *wchan = "nlmrcv";
	const char* protofmly;
	struct sockaddr_storage ss;
	struct socket *so;
	CLIENT *rpcb;
	struct timeval timo;
	RPCB parms;
	char *uaddr;
	enum clnt_stat stat = RPC_SUCCESS;
	int rpcvers = RPCBVERS4;
	bool_t do_tcp = FALSE;
	bool_t tryagain = FALSE;
	struct portmap mapping;
	u_short port = 0;
	memcpy(&ss, sa, sa->sa_len);
	switch (ss.ss_family) {
	case AF_INET:
		((struct sockaddr_in *)&ss)->sin_port = htons(111);
		protofmly = "inet";
		so = nlm_socket;
		break;
#ifdef INET6
	case AF_INET6:
		((struct sockaddr_in6 *)&ss)->sin6_port = htons(111);
		protofmly = "inet6";
		so = nlm_socket6;
		break;
#endif
	default:
		return (NULL);
	}
	rpcb = clnt_dg_create(so, (struct sockaddr *)&ss,
	    RPCBPROG, rpcvers, 0, 0);
	if (!rpcb)
		return (NULL);
try_tcp:
	parms.r_prog = prog;
	parms.r_vers = vers;
	if (do_tcp)
		parms.r_netid = "tcp";
	else
		parms.r_netid = "udp";
	parms.r_addr = "";
	parms.r_owner = "";
	timo.tv_sec = 25;
	timo.tv_usec = 0;
again:
	switch (rpcvers) {
	case RPCBVERS4:
	case RPCBVERS:
		uaddr = NULL;
		stat = CLNT_CALL(rpcb, (rpcprog_t) RPCBPROC_GETADDR,
		    (xdrproc_t) xdr_rpcb, &parms,
		    (xdrproc_t) xdr_wrapstring, &uaddr, timo);
		if (stat == RPC_SUCCESS) {
			struct netbuf *a;
			a = __rpc_uaddr2taddr_af(ss.ss_family, uaddr);
			if (!a) {
				tryagain = TRUE;
			} else {
				tryagain = FALSE;
				memcpy(&ss, a->buf, a->len);
				free(a->buf, M_RPC);
				free(a, M_RPC);
				xdr_free((xdrproc_t) xdr_wrapstring, &uaddr);
			}
		}
		if (tryagain || stat == RPC_PROGVERSMISMATCH) {
			if (rpcvers == RPCBVERS4)
				rpcvers = RPCBVERS;
			else if (rpcvers == RPCBVERS)
				rpcvers = PMAPVERS;
			CLNT_CONTROL(rpcb, CLSET_VERS, &rpcvers);
			goto again;
		}
		break;
	case PMAPVERS:
		mapping.pm_prog = parms.r_prog;
		mapping.pm_vers = parms.r_vers;
		mapping.pm_prot = do_tcp ? IPPROTO_TCP : IPPROTO_UDP;
		mapping.pm_port = 0;
		stat = CLNT_CALL(rpcb, (rpcprog_t) PMAPPROC_GETPORT,
		    (xdrproc_t) xdr_portmap, &mapping,
		    (xdrproc_t) xdr_u_short, &port, timo);
		if (stat == RPC_SUCCESS) {
			switch (ss.ss_family) {
			case AF_INET:
				((struct sockaddr_in *)&ss)->sin_port =
					htons(port);
				break;
#ifdef INET6
			case AF_INET6:
				((struct sockaddr_in6 *)&ss)->sin6_port =
					htons(port);
				break;
#endif
			}
		}
		break;
	default:
		panic("invalid rpcvers %d", rpcvers);
	}
	switch (ss.ss_family) {
	case AF_INET:
		port = ((struct sockaddr_in *)&ss)->sin_port;
		break;
#ifdef INET6
	case AF_INET6:
		port = ((struct sockaddr_in6 *)&ss)->sin6_port;
		break;
#endif
	}
	if (stat != RPC_SUCCESS || !port) {
		if (stat == RPC_SUCCESS && !do_tcp) {
			do_tcp = TRUE;
			goto try_tcp;
		}
		NLM_ERR("NLM: failed to contact remote rpcbind, "
		    "stat = %d, port = %d\n", (int) stat, port);
		CLNT_DESTROY(rpcb);
		return (NULL);
	}
	if (do_tcp) {
		struct netconfig *nconf = NULL;
		CLNT_DESTROY(rpcb);
		switch (ss.ss_family) {
		case AF_INET:
			nconf = getnetconfigent("tcp");
			break;
#ifdef INET6
		case AF_INET6:
			nconf = getnetconfigent("tcp6");
			break;
#endif
		}
		rpcb = clnt_reconnect_create(nconf, (struct sockaddr *)&ss,
		    prog, vers, 0, 0);
		CLNT_CONTROL(rpcb, CLSET_WAITCHAN, wchan);
		rpcb->cl_auth = nlm_auth;
	} else {
		CLNT_CONTROL(rpcb, CLSET_SVC_ADDR, &ss);
		CLNT_CONTROL(rpcb, CLSET_PROG, &prog);
		CLNT_CONTROL(rpcb, CLSET_VERS, &vers);
		CLNT_CONTROL(rpcb, CLSET_WAITCHAN, wchan);
		rpcb->cl_auth = nlm_auth;
	}
	return (rpcb);
}
static CLIENT * nlm_get_rpc ( struct sockaddr * sa , rpcprog_t prog , rpcvers_t vers ) { char * wchan = " " ; const char * protofmly ; struct sockaddr_storage ss ; struct socket * so ; CLIENT * rpcb ; struct timeval timo ; RPCB parms ; char * uaddr ; enum clnt_stat stat = RPC_SUCCESS ; int rpcvers = RPCBVERS4 ; bool_t do_tcp = FALSE ; bool_t tryagain = FALSE ; struct portmap mapping ; u_short port = 0 ; memcpy ( & ss , sa , sa -> sa_len ) ; switch ( ss . ss_family ) { case AF_INET : ( ( struct sockaddr_in * ) & ss ) -> sin_port = htons ( 111 ) ; protofmly = " " ; so = nlm_socket ; break ; #ifdef INET6 case AF_INET6 : ( ( struct sockaddr_in6 * ) & ss ) -> sin6_port = htons ( 111 ) ; protofmly = " " ; so = nlm_socket6 ; break ; #endif default : return ( NULL ) ; } rpcb = clnt_dg_create ( so , ( struct sockaddr * ) & ss , RPCBPROG , rpcvers , 0 , 0 ) ; if ( ! rpcb ) return ( NULL ) ; try_tcp : parms . r_prog = prog ; parms . r_vers = vers ; if ( do_tcp ) parms . r_netid = " " ; else parms . r_netid = " " ; parms . r_addr = " " ; parms . r_owner = " " ; timo . tv_sec = 25 ; timo . tv_usec = 0 ; again : switch ( rpcvers ) { case RPCBVERS4 : case RPCBVERS : uaddr = NULL ; stat = CLNT_CALL ( rpcb , ( rpcprog_t ) RPCBPROC_GETADDR , ( xdrproc_t ) xdr_rpcb , & parms , ( xdrproc_t ) xdr_wrapstring , & uaddr , timo ) ; if ( stat == RPC_SUCCESS ) { struct netbuf * a ; a = __rpc_uaddr2taddr_af ( ss . ss_family , uaddr ) ; if ( ! a ) { tryagain = TRUE ; } else { tryagain = FALSE ; memcpy ( & ss , a -> buf , a -> len ) ; free ( a -> buf , M_RPC ) ; free ( a , M_RPC ) ; xdr_free ( ( xdrproc_t ) xdr_wrapstring , & uaddr ) ; } } if ( tryagain || stat == RPC_PROGVERSMISMATCH ) { if ( rpcvers == RPCBVERS4 ) rpcvers = RPCBVERS ; else if ( rpcvers == RPCBVERS ) rpcvers = PMAPVERS ; CLNT_CONTROL ( rpcb , CLSET_VERS , & rpcvers ) ; goto again ; } break ; case PMAPVERS : mapping . pm_prog = parms . r_prog ; mapping . pm_vers = parms . r_vers ; mapping . pm_prot = do_tcp ? IPPROTO_TCP : IPPROTO_UDP ; mapping . pm_port = 0 ; stat = CLNT_CALL ( rpcb , ( rpcprog_t ) PMAPPROC_GETPORT , ( xdrproc_t ) xdr_portmap , & mapping , ( xdrproc_t ) xdr_u_short , & port , timo ) ; if ( stat == RPC_SUCCESS ) { switch ( ss . ss_family ) { case AF_INET : ( ( struct sockaddr_in * ) & ss ) -> sin_port = htons ( port ) ; break ; #ifdef INET6 case AF_INET6 : ( ( struct sockaddr_in6 * ) & ss ) -> sin6_port = htons ( port ) ; break ; #endif } } break ; default : panic ( " " , rpcvers ) ; } switch ( ss . ss_family ) { case AF_INET : port = ( ( struct sockaddr_in * ) & ss ) -> sin_port ; break ; #ifdef INET6 case AF_INET6 : port = ( ( struct sockaddr_in6 * ) & ss ) -> sin6_port ; break ; #endif } if ( stat != RPC_SUCCESS || ! port ) { if ( stat == RPC_SUCCESS && ! do_tcp ) { do_tcp = TRUE ; goto try_tcp ; } NLM_ERR ( " " " \n " , ( int ) stat , port ) ; CLNT_DESTROY ( rpcb ) ; return ( NULL ) ; } if ( do_tcp ) { struct netconfig * nconf = NULL ; CLNT_DESTROY ( rpcb ) ; switch ( ss . ss_family ) { case AF_INET : nconf = getnetconfigent ( " " ) ; break ; #ifdef INET6 case AF_INET6 : nconf = getnetconfigent ( " " ) ; break ; #endif } rpcb = clnt_reconnect_create ( nconf , ( struct sockaddr * ) & ss , prog , vers , 0 , 0 ) ; CLNT_CONTROL ( rpcb , CLSET_WAITCHAN , wchan ) ; rpcb -> cl_auth = nlm_auth ; } else { CLNT_CONTROL ( rpcb , CLSET_SVC_ADDR , & ss ) ; CLNT_CONTROL ( rpcb , CLSET_PROG , & prog ) ; CLNT_CONTROL ( rpcb , CLSET_VERS , & vers ) ; CLNT_CONTROL ( rpcb , CLSET_WAITCHAN , wchan ) ; rpcb -> cl_auth = nlm_auth ; } return ( rpcb ) ; }
Create an RPC client handle for the given (address,prog,vers)
 triple using UDP.
Create an RPC client handle for the given ( address prog vers ) triple using UDP .
/*
	 * First we need to contact the remote RPCBIND service to find
	 * the right port.
	 */ /*
		 * Unsupported address family - fail.
		 */ /*
	 * Use the default timeout.
	 */ /*
		 * Try RPCBIND 4 then 3.
		 */ /*
			 * We have a reply from the remote RPCBIND - turn it
			 * into an appropriate address and make a new client
			 * that can talk to the remote NLM.
			 *
			 * XXX fixup IPv6 scope ID.
			 */ /*
		 * Try portmap.
		 */ /*
	 * We may have a positive response from the portmapper, but the NLM
	 * service was not found. Make sure we received a valid port.
	 */ /*
		 * If we were able to talk to rpcbind or portmap, but the udp
		 * variant wasn't available, ask about tcp.
		 *
		 * XXX - We could also check for a TCP portmapper, but
		 * if the host is running a portmapper at all, we should be able
		 * to hail it over UDP.
		 */ /* Otherwise, bad news. */ /*
		 * Destroy the UDP client we used to speak to rpcbind and
		 * recreate as a TCP client.
		 */ /*
		 * Re-use the client we used to speak to rpcbind.
		 */