FreeBSD/sys/rpc/clnt_vc.c
/*
 * Create a client handle for a connection.
 * Default options are set, which the user can change using clnt_control()'s.
 * The rpc/vc package does buffering similar to stdio, so the client
 * must pick send and receive buffer sizes, 0 => use the default.
 * NB: fd is copied into a private area.
 * NB: The rpch->cl_auth is set null authentication. Caller may wish to
 * set this something more useful.
 *
 * fd should be an open socket
 */
Create a client handle for a connection.
Default options are set, which the user can change using clnt_control()'s.
The rpc/vc package does buffering similar to stdio, so the client
must pick send and receive buffer sizes, 0 => use the default.
NB: fd is copied into a private area.
NB: The rpch->cl_auth is set null authentication. Caller may wish to
set this something more useful.

fd should be an open socket
Create a client handle for a connection . Default options are set which the user can change using clnt_control () ' s . The rpc / vc package does buffering similar to stdio so the client must pick send and receive buffer sizes 0 = > use the default . NB : fd is copied into a private area . NB : The rpch - > cl_auth is set null authentication . Caller may wish to set this something more useful . fd should be an open socket
CLIENT *
clnt_vc_create(
	struct socket *so,		
	struct sockaddr *raddr,		
	const rpcprog_t prog,		
	const rpcvers_t vers,		
	size_t sendsz,			
	size_t recvsz,			
	int intrflag)			
{
	CLIENT *cl;			
	struct ct_data *ct = NULL;	
	struct timeval now;
	struct rpc_msg call_msg;
	static uint32_t disrupt;
	struct __rpc_sockinfo si;
	XDR xdrs;
	int error, interrupted, one = 1, sleep_flag;
	struct sockopt sopt;
	if (disrupt == 0)
		disrupt = (uint32_t)(long)raddr;
	cl = (CLIENT *)mem_alloc(sizeof (*cl));
	ct = (struct ct_data *)mem_alloc(sizeof (*ct));
	mtx_init(&ct->ct_lock, "ct->ct_lock", NULL, MTX_DEF);
	ct->ct_threads = 0;
	ct->ct_closing = FALSE;
	ct->ct_closed = FALSE;
	ct->ct_upcallrefs = 0;
	if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) {
		error = soconnect(so, raddr, curthread);
		SOCK_LOCK(so);
		interrupted = 0;
		sleep_flag = PSOCK;
		if (intrflag != 0)
			sleep_flag |= PCATCH;
		while ((so->so_state & SS_ISCONNECTING)
		    && so->so_error == 0) {
			error = msleep(&so->so_timeo, SOCK_MTX(so),
			    sleep_flag, "connec", 0);
			if (error) {
				if (error == EINTR || error == ERESTART)
					interrupted = 1;
				break;
			}
		}
		if (error == 0) {
			error = so->so_error;
			so->so_error = 0;
		}
		SOCK_UNLOCK(so);
		if (error) {
			if (!interrupted)
				so->so_state &= ~SS_ISCONNECTING;
			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
			rpc_createerr.cf_error.re_errno = error;
			goto err;
		}
	}
	if (!__rpc_socket2sockinfo(so, &si)) {
		goto err;
	}
	if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
		bzero(&sopt, sizeof(sopt));
		sopt.sopt_dir = SOPT_SET;
		sopt.sopt_level = SOL_SOCKET;
		sopt.sopt_name = SO_KEEPALIVE;
		sopt.sopt_val = &one;
		sopt.sopt_valsize = sizeof(one);
		sosetopt(so, &sopt);
	}
	if (so->so_proto->pr_protocol == IPPROTO_TCP) {
		bzero(&sopt, sizeof(sopt));
		sopt.sopt_dir = SOPT_SET;
		sopt.sopt_level = IPPROTO_TCP;
		sopt.sopt_name = TCP_NODELAY;
		sopt.sopt_val = &one;
		sopt.sopt_valsize = sizeof(one);
		sosetopt(so, &sopt);
	}
	ct->ct_closeit = FALSE;
	ct->ct_socket = so;
	ct->ct_wait.tv_sec = -1;
	ct->ct_wait.tv_usec = -1;
	memcpy(&ct->ct_addr, raddr, raddr->sa_len);
	getmicrotime(&now);
	ct->ct_xid = ((uint32_t)++disrupt) ^ __RPC_GETXID(&now);
	call_msg.rm_xid = ct->ct_xid;
	call_msg.rm_direction = CALL;
	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
	call_msg.rm_call.cb_prog = (uint32_t)prog;
	call_msg.rm_call.cb_vers = (uint32_t)vers;
	xdrmem_create(&xdrs, ct->ct_mcallc, MCALL_MSG_SIZE,
	    XDR_ENCODE);
	if (! xdr_callhdr(&xdrs, &call_msg)) {
		if (ct->ct_closeit) {
			soclose(ct->ct_socket);
		}
		goto err;
	}
	ct->ct_mpos = XDR_GETPOS(&xdrs);
	XDR_DESTROY(&xdrs);
	ct->ct_waitchan = "rpcrecv";
	ct->ct_waitflag = 0;
	sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz);
	recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz);
	error = soreserve(ct->ct_socket, sendsz, recvsz);
	if (error != 0) {
		if (ct->ct_closeit) {
			soclose(ct->ct_socket);
		}
		goto err;
	}
	cl->cl_refs = 1;
	cl->cl_ops = &clnt_vc_ops;
	cl->cl_private = ct;
	cl->cl_auth = authnone_create();
	SOCKBUF_LOCK(&ct->ct_socket->so_rcv);
	soupcall_set(ct->ct_socket, SO_RCV, clnt_vc_soupcall, ct);
	SOCKBUF_UNLOCK(&ct->ct_socket->so_rcv);
	ct->ct_record = NULL;
	ct->ct_record_resid = 0;
	TAILQ_INIT(&ct->ct_pending);
	return (cl);
err:
	mtx_destroy(&ct->ct_lock);
	mem_free(ct, sizeof (struct ct_data));
	mem_free(cl, sizeof (CLIENT));
	return ((CLIENT *)NULL);
}
CLIENT * clnt_vc_create ( struct socket * so , struct sockaddr * raddr , const rpcprog_t prog , const rpcvers_t vers , size_t sendsz , size_t recvsz , int intrflag ) { CLIENT * cl ; struct ct_data * ct = NULL ; struct timeval now ; struct rpc_msg call_msg ; static uint32_t disrupt ; struct __rpc_sockinfo si ; XDR xdrs ; int error , interrupted , one = 1 , sleep_flag ; struct sockopt sopt ; if ( disrupt == 0 ) disrupt = ( uint32_t ) ( long ) raddr ; cl = ( CLIENT * ) mem_alloc ( sizeof ( * cl ) ) ; ct = ( struct ct_data * ) mem_alloc ( sizeof ( * ct ) ) ; mtx_init ( & ct -> ct_lock , " " , NULL , MTX_DEF ) ; ct -> ct_threads = 0 ; ct -> ct_closing = FALSE ; ct -> ct_closed = FALSE ; ct -> ct_upcallrefs = 0 ; if ( ( so -> so_state & ( SS_ISCONNECTED | SS_ISCONFIRMING ) ) == 0 ) { error = soconnect ( so , raddr , curthread ) ; SOCK_LOCK ( so ) ; interrupted = 0 ; sleep_flag = PSOCK ; if ( intrflag != 0 ) sleep_flag |= PCATCH ; while ( ( so -> so_state & SS_ISCONNECTING ) && so -> so_error == 0 ) { error = msleep ( & so -> so_timeo , SOCK_MTX ( so ) , sleep_flag , " " , 0 ) ; if ( error ) { if ( error == EINTR || error == ERESTART ) interrupted = 1 ; break ; } } if ( error == 0 ) { error = so -> so_error ; so -> so_error = 0 ; } SOCK_UNLOCK ( so ) ; if ( error ) { if ( ! interrupted ) so -> so_state &= ~ SS_ISCONNECTING ; rpc_createerr . cf_stat = RPC_SYSTEMERROR ; rpc_createerr . cf_error . re_errno = error ; goto err ; } } if ( ! __rpc_socket2sockinfo ( so , & si ) ) { goto err ; } if ( so -> so_proto -> pr_flags & PR_CONNREQUIRED ) { bzero ( & sopt , sizeof ( sopt ) ) ; sopt . sopt_dir = SOPT_SET ; sopt . sopt_level = SOL_SOCKET ; sopt . sopt_name = SO_KEEPALIVE ; sopt . sopt_val = & one ; sopt . sopt_valsize = sizeof ( one ) ; sosetopt ( so , & sopt ) ; } if ( so -> so_proto -> pr_protocol == IPPROTO_TCP ) { bzero ( & sopt , sizeof ( sopt ) ) ; sopt . sopt_dir = SOPT_SET ; sopt . sopt_level = IPPROTO_TCP ; sopt . sopt_name = TCP_NODELAY ; sopt . sopt_val = & one ; sopt . sopt_valsize = sizeof ( one ) ; sosetopt ( so , & sopt ) ; } ct -> ct_closeit = FALSE ; ct -> ct_socket = so ; ct -> ct_wait . tv_sec = -1 ; ct -> ct_wait . tv_usec = -1 ; memcpy ( & ct -> ct_addr , raddr , raddr -> sa_len ) ; getmicrotime ( & now ) ; ct -> ct_xid = ( ( uint32_t ) ++ disrupt ) ^ __RPC_GETXID ( & now ) ; call_msg . rm_xid = ct -> ct_xid ; call_msg . rm_direction = CALL ; call_msg . rm_call . cb_rpcvers = RPC_MSG_VERSION ; call_msg . rm_call . cb_prog = ( uint32_t ) prog ; call_msg . rm_call . cb_vers = ( uint32_t ) vers ; xdrmem_create ( & xdrs , ct -> ct_mcallc , MCALL_MSG_SIZE , XDR_ENCODE ) ; if ( ! xdr_callhdr ( & xdrs , & call_msg ) ) { if ( ct -> ct_closeit ) { soclose ( ct -> ct_socket ) ; } goto err ; } ct -> ct_mpos = XDR_GETPOS ( & xdrs ) ; XDR_DESTROY ( & xdrs ) ; ct -> ct_waitchan = " " ; ct -> ct_waitflag = 0 ; sendsz = __rpc_get_t_size ( si . si_af , si . si_proto , ( int ) sendsz ) ; recvsz = __rpc_get_t_size ( si . si_af , si . si_proto , ( int ) recvsz ) ; error = soreserve ( ct -> ct_socket , sendsz , recvsz ) ; if ( error != 0 ) { if ( ct -> ct_closeit ) { soclose ( ct -> ct_socket ) ; } goto err ; } cl -> cl_refs = 1 ; cl -> cl_ops = & clnt_vc_ops ; cl -> cl_private = ct ; cl -> cl_auth = authnone_create ( ) ; SOCKBUF_LOCK ( & ct -> ct_socket -> so_rcv ) ; soupcall_set ( ct -> ct_socket , SO_RCV , clnt_vc_soupcall , ct ) ; SOCKBUF_UNLOCK ( & ct -> ct_socket -> so_rcv ) ; ct -> ct_record = NULL ; ct -> ct_record_resid = 0 ; TAILQ_INIT ( & ct -> ct_pending ) ; return ( cl ) ; err : mtx_destroy ( & ct -> ct_lock ) ; mem_free ( ct , sizeof ( struct ct_data ) ) ; mem_free ( cl , sizeof ( CLIENT ) ) ; return ( ( CLIENT * ) NULL ) ; }
Create a client handle for a connection.
Create a client handle for a connection .
/* open file descriptor */ /* servers address */ /* program number */ /* version number */ /* buffer recv size */ /* buffer send size */ /* interruptible */ /* client handle */ /* client handle */ /*
	 * Set up private data struct
	 */ /*
	 * Initialize call message
	 */ /*
	 * pre-serialize the static part of the call msg and stash it away
	 */ /*
	 * Create a client handle which uses xdrrec for serialization
	 * and authnone for authentication.
	 */