Exemple #1
0
/*
 * Field reply to call to mountd
 */
int
pickup_rpc_reply(voidp pkt, int len, voidp where, XDRPROC_T_TYPE where_xdr)
{
    XDR reply_xdr;
    int ok;
    struct rpc_err err;
    struct rpc_msg reply_msg;
    int error = 0;

    /* memset((voidp) &err, 0, sizeof(err)); */
    memset((voidp) &reply_msg, 0, sizeof(reply_msg));
    memset((voidp) &reply_xdr, 0, sizeof(reply_xdr));

    reply_msg.acpted_rply.ar_results.where = where;
    reply_msg.acpted_rply.ar_results.proc = where_xdr;

    xdrmem_create(&reply_xdr, pkt, len, XDR_DECODE);

    ok = xdr_replymsg(&reply_xdr, &reply_msg);
    if (!ok) {
        error = EIO;
        goto drop;
    }
    _seterr_reply(&reply_msg, &err);
    if (err.re_status != RPC_SUCCESS) {
        error = EIO;
        goto drop;
    }

drop:
    if (reply_msg.rm_reply.rp_stat == MSG_ACCEPTED &&
            reply_msg.acpted_rply.ar_verf.oa_base) {
        reply_xdr.x_op = XDR_FREE;
        (void) xdr_opaque_auth(&reply_xdr,
                               &reply_msg.acpted_rply.ar_verf);
    }
    xdr_destroy(&reply_xdr);

    return error;
}
Exemple #2
0
static enum clnt_stat
clnt_vc_call(CLIENT *cl, rpcproc_t proc, xdrproc_t xdr_args, void *args_ptr,
    xdrproc_t xdr_results, void *results_ptr, struct timeval timeout)
{
	struct ct_data *ct = (struct ct_data *) cl->cl_private;
	XDR *xdrs = &(ct->ct_xdrs);
	struct rpc_msg reply_msg;
	u_int32_t x_id;
	u_int32_t *msg_x_id = &ct->ct_u.ct_mcalli;    /* yuk */
	bool_t shipnow;
	int refreshes = 2;
	sigset_t mask, newmask;
	int rpc_lock_value;
	bool_t reply_stat;

	assert(cl != NULL);

	sigfillset(&newmask);
	thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
	mutex_lock(&clnt_fd_lock);
	while (vc_fd_locks[ct->ct_fd])
		cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
	if (__isthreaded)
                rpc_lock_value = 1;
        else
                rpc_lock_value = 0;
	vc_fd_locks[ct->ct_fd] = rpc_lock_value;
	mutex_unlock(&clnt_fd_lock);
	if (!ct->ct_waitset) {
		/* If time is not within limits, we ignore it. */
		if (time_not_ok(&timeout) == FALSE)
			ct->ct_wait = timeout;
	}

	shipnow =
	    (xdr_results == NULL && timeout.tv_sec == 0
	    && timeout.tv_usec == 0) ? FALSE : TRUE;

call_again:
	xdrs->x_op = XDR_ENCODE;
	ct->ct_error.re_status = RPC_SUCCESS;
	x_id = ntohl(--(*msg_x_id));

	if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) {
		if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) ||
		    (! XDR_PUTINT32(xdrs, &proc)) ||
		    (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
		    (! (*xdr_args)(xdrs, args_ptr))) {
			if (ct->ct_error.re_status == RPC_SUCCESS)
				ct->ct_error.re_status = RPC_CANTENCODEARGS;
			(void)xdrrec_endofrecord(xdrs, TRUE);
			release_fd_lock(ct->ct_fd, mask);
			return (ct->ct_error.re_status);
		}
	} else {
		*(uint32_t *) &ct->ct_u.ct_mcallc[ct->ct_mpos] = htonl(proc);
		if (! __rpc_gss_wrap(cl->cl_auth, ct->ct_u.ct_mcallc,
			ct->ct_mpos + sizeof(uint32_t),
			xdrs, xdr_args, args_ptr)) {
			if (ct->ct_error.re_status == RPC_SUCCESS)
				ct->ct_error.re_status = RPC_CANTENCODEARGS;
			(void)xdrrec_endofrecord(xdrs, TRUE);
			release_fd_lock(ct->ct_fd, mask);
			return (ct->ct_error.re_status);
		}
	}
	if (! xdrrec_endofrecord(xdrs, shipnow)) {
		release_fd_lock(ct->ct_fd, mask);
		return (ct->ct_error.re_status = RPC_CANTSEND);
	}
	if (! shipnow) {
		release_fd_lock(ct->ct_fd, mask);
		return (RPC_SUCCESS);
	}
	/*
	 * Hack to provide rpc-based message passing
	 */
	if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
		release_fd_lock(ct->ct_fd, mask);
		return(ct->ct_error.re_status = RPC_TIMEDOUT);
	}


	/*
	 * Keep receiving until we get a valid transaction id
	 */
	xdrs->x_op = XDR_DECODE;
	while (TRUE) {
		reply_msg.acpted_rply.ar_verf = _null_auth;
		reply_msg.acpted_rply.ar_results.where = NULL;
		reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
		if (! xdrrec_skiprecord(xdrs)) {
			release_fd_lock(ct->ct_fd, mask);
			return (ct->ct_error.re_status);
		}
		/* now decode and validate the response header */
		if (! xdr_replymsg(xdrs, &reply_msg)) {
			if (ct->ct_error.re_status == RPC_SUCCESS)
				continue;
			release_fd_lock(ct->ct_fd, mask);
			return (ct->ct_error.re_status);
		}
		if (reply_msg.rm_xid == x_id)
			break;
	}

	/*
	 * process header
	 */
	_seterr_reply(&reply_msg, &(ct->ct_error));
	if (ct->ct_error.re_status == RPC_SUCCESS) {
		if (! AUTH_VALIDATE(cl->cl_auth,
		    &reply_msg.acpted_rply.ar_verf)) {
			ct->ct_error.re_status = RPC_AUTHERROR;
			ct->ct_error.re_why = AUTH_INVALIDRESP;
		} else {
			if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) {
				reply_stat = (*xdr_results)(xdrs, results_ptr);
			} else {
				reply_stat = __rpc_gss_unwrap(cl->cl_auth,
				    xdrs, xdr_results, results_ptr);
			}
			if (! reply_stat) {
				if (ct->ct_error.re_status == RPC_SUCCESS)
					ct->ct_error.re_status =
						RPC_CANTDECODERES;
			}
		}
		/* free verifier ... */
		if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
			xdrs->x_op = XDR_FREE;
			(void)xdr_opaque_auth(xdrs,
			    &(reply_msg.acpted_rply.ar_verf));
		}
	}  /* end successful completion */
	else {
		/* maybe our credentials need to be refreshed ... */
		if (refreshes-- && AUTH_REFRESH(cl->cl_auth, &reply_msg))
			goto call_again;
	}  /* end of unsuccessful completion */
	release_fd_lock(ct->ct_fd, mask);
	return (ct->ct_error.re_status);
}
Exemple #3
0
enum clnt_stat qrpc_clnt_raw_call(CLIENT *cl, u_long proc, xdrproc_t xargs, caddr_t argsp,
					xdrproc_t xresults, caddr_t resultsp,
					struct timeval utimeout)
{
	struct qrpc_clnt_raw_priv *priv = (struct qrpc_clnt_raw_priv *)cl->cl_private;
	XDR *xdrs_out = &priv->xdrs_out;
	XDR *xdrs_in = &priv->xdrs_in;
	struct rpc_msg reply_msg;
	struct timeval curr_time;
	struct qrpc_frame_hdr *hdr;
	uint16_t tmp;

	if (xargs) {
		xdrs_out->x_op = XDR_ENCODE;
		XDR_SETPOS(xdrs_out, priv->xdrs_outpos);

		if ((!XDR_PUTLONG(xdrs_out, (long *)&proc)) ||
				(!AUTH_MARSHALL(cl->cl_auth, xdrs_out)) ||
				(!(*xargs) (xdrs_out, argsp))) {
			priv->rpc_error.re_status = RPC_CANTENCODEARGS;
			return priv->rpc_error.re_status;
		}
		tmp = ntohs(priv->out_hdr.seq);
		priv->out_hdr.seq = htons(tmp + 1);
		if (qrpc_clnt_raw_call_send(priv, XDR_GETPOS(xdrs_out)) < 0) {
			return priv->rpc_error.re_status;
		}
	}

	if (gettimeofday(&curr_time, NULL) < 0) {
		priv->rpc_error.re_status = RPC_SYSTEMERROR;
		return priv->rpc_error.re_status;
	}
	utimeout.tv_sec += curr_time.tv_sec;
	/* Waiting for reply */
	do {
		if (qrpc_clnt_raw_call_recv(priv) < 0) {
			if (priv->rpc_error.re_status == RPC_TIMEDOUT)
				continue;
			else
				break;
		}

		hdr = (struct qrpc_frame_hdr *)priv->inbuf;
		if (xargs && priv->out_hdr.seq != hdr->seq) {
			continue;
		}

		xdrs_in->x_op = XDR_DECODE;
		XDR_SETPOS(xdrs_in, 0);

		reply_msg.acpted_rply.ar_verf = _null_auth;
		reply_msg.acpted_rply.ar_results.where = resultsp;
		reply_msg.acpted_rply.ar_results.proc = xresults;

		if (xdr_replymsg(xdrs_in, &reply_msg)) {
			if (reply_msg.rm_xid != (unsigned long)getpid()) {
				continue;
			}
			_seterr_reply(&reply_msg, &priv->rpc_error);
			if (priv->rpc_error.re_status == RPC_SUCCESS) {
				if (!AUTH_VALIDATE(cl->cl_auth, &reply_msg.acpted_rply.ar_verf)) {
					priv->rpc_error.re_status = RPC_AUTHERROR;
					priv->rpc_error.re_why = AUTH_INVALIDRESP;
				}
				break;
			}
		} else {
			priv->rpc_error.re_status = RPC_CANTDECODERES;
		}
	} while ((gettimeofday(&curr_time, NULL) == 0) && (curr_time.tv_sec < utimeout.tv_sec));

	return priv->rpc_error.re_status;
}
Exemple #4
0
static enum clnt_stat
clnttcp_call(CLIENT *h, u_long proc, xdrproc_t xdr_args, caddr_t args_ptr,
    xdrproc_t xdr_results, caddr_t results_ptr, struct timeval timeout)
{
	struct ct_data *ct = (struct ct_data *) h->cl_private;
	XDR *xdrs = &(ct->ct_xdrs);
	struct rpc_msg reply_msg;
	u_long x_id;
	u_int32_t *msg_x_id = (u_int32_t *)(ct->ct_mcall);	/* yuk */
	bool_t shipnow;
	int refreshes = 2;

	if (!ct->ct_waitset) {
		ct->ct_wait = timeout;
	}

	shipnow =
	    (xdr_results == NULL && timeout.tv_sec == 0
	    && timeout.tv_usec == 0) ? FALSE : TRUE;

call_again:
	xdrs->x_op = XDR_ENCODE;
	ct->ct_error.re_status = RPC_SUCCESS;
	x_id = ntohl(--(*msg_x_id));
	if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) ||
	    (! XDR_PUTLONG(xdrs, (long *)&proc)) ||
	    (! AUTH_MARSHALL(h->cl_auth, xdrs)) ||
	    (! (*xdr_args)(xdrs, args_ptr))) {
		if (ct->ct_error.re_status == RPC_SUCCESS)
			ct->ct_error.re_status = RPC_CANTENCODEARGS;
		(void)xdrrec_endofrecord(xdrs, TRUE);
		return (ct->ct_error.re_status);
	}
	if (! xdrrec_endofrecord(xdrs, shipnow))
		return (ct->ct_error.re_status = RPC_CANTSEND);
	if (! shipnow)
		return (RPC_SUCCESS);
	/*
	 * Hack to provide rpc-based message passing
	 */
	if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
		return(ct->ct_error.re_status = RPC_TIMEDOUT);
	}


	/*
	 * Keep receiving until we get a valid transaction id
	 */
	xdrs->x_op = XDR_DECODE;
	while (TRUE) {
		reply_msg.acpted_rply.ar_verf = _null_auth;
		reply_msg.acpted_rply.ar_results.where = NULL;
		reply_msg.acpted_rply.ar_results.proc = xdr_void;
		if (! xdrrec_skiprecord(xdrs))
			return (ct->ct_error.re_status);
		/* now decode and validate the response header */
		if (! xdr_replymsg(xdrs, &reply_msg)) {
			if (ct->ct_error.re_status == RPC_SUCCESS)
				continue;
			return (ct->ct_error.re_status);
		}
		if (reply_msg.rm_xid == x_id)
			break;
	}

	/*
	 * process header
	 */
	_seterr_reply(&reply_msg, &(ct->ct_error));
	if (ct->ct_error.re_status == RPC_SUCCESS) {
		if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) {
			ct->ct_error.re_status = RPC_AUTHERROR;
			ct->ct_error.re_why = AUTH_INVALIDRESP;
		} else if (! (*xdr_results)(xdrs, results_ptr)) {
			if (ct->ct_error.re_status == RPC_SUCCESS)
				ct->ct_error.re_status = RPC_CANTDECODERES;
		}
		/* free verifier ... */
		if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
			xdrs->x_op = XDR_FREE;
			(void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf));
		}
	}  /* end successful completion */
	else {
		/* maybe our credentials need to be refreshed ... */
		if (refreshes-- && AUTH_REFRESH(h->cl_auth))
			goto call_again;
	}  /* end of unsuccessful completion */
	return (ct->ct_error.re_status);
}
static enum clnt_stat clntudp_call(CLIENT *cl, unsigned long proc, 
	xdrproc_t xargs, char* argsp, 
	xdrproc_t xresults, char* resultsp, 
	struct timeval utimeout)
{
	register struct cu_data *cu = (struct cu_data *) cl->cl_private;
	register XDR *xdrs;
	register int outlen;
	register int inlen;
	socklen_t fromlen;

	struct sockaddr_in from;
	struct rpc_msg reply_msg;
	XDR reply_xdrs;
	bool_t ok;
	int nrefreshes = 2;			/* number of times to refresh cred */

call_again:
	xdrs = &(cu->cu_outxdrs);
	xdrs->x_op = XDR_ENCODE;
	XDR_SETPOS(xdrs, cu->cu_xdrpos);

	/*
	 * the transaction is the first thing in the out buffer
	 */
	(*(unsigned long *) (cu->cu_outbuf))++;

	if ((!XDR_PUTLONG(xdrs, (long *) &proc)) ||
			(!AUTH_MARSHALL(cl->cl_auth, xdrs)) || (!(*xargs) (xdrs, argsp)))
		return (cu->cu_error.re_status = RPC_CANTENCODEARGS);
	outlen = (int) XDR_GETPOS(xdrs);

send_again:
	if (sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0,
			   (struct sockaddr *) &(cu->cu_raddr), cu->cu_rlen)
			!= outlen)
	{
		cu->cu_error.re_errno = errno;
		return (cu->cu_error.re_status = RPC_CANTSEND);
	}

	/*
	 * sub-optimal code appears here because we have
	 * some clock time to spare while the packets are in flight.
	 * (We assume that this is actually only executed once.)
	 */
	reply_msg.acpted_rply.ar_verf = _null_auth;
	reply_msg.acpted_rply.ar_results.where = resultsp;
	reply_msg.acpted_rply.ar_results.proc = xresults;

	/* do recv */
	do
	{
		fromlen = sizeof(struct sockaddr);

		inlen = recvfrom(cu->cu_sock, cu->cu_inbuf,
						 (int) cu->cu_recvsz, 0,
						 (struct sockaddr *) &from, &fromlen);
	}while (inlen < 0 && errno == EINTR);

	if (inlen < 4)
	{
		rt_kprintf("recv error, len %d\n", inlen);
		cu->cu_error.re_errno = errno;
		return (cu->cu_error.re_status = RPC_CANTRECV);
	}

	/* see if reply transaction id matches sent id */
	if (*((uint32_t *) (cu->cu_inbuf)) != *((uint32_t *) (cu->cu_outbuf)))
		goto send_again;

	/* we now assume we have the proper reply */

	/*
	 * now decode and validate the response
	 */
	xdrmem_create(&reply_xdrs, cu->cu_inbuf, (unsigned int) inlen, XDR_DECODE);
	ok = xdr_replymsg(&reply_xdrs, &reply_msg);
	/* XDR_DESTROY(&reply_xdrs);  save a few cycles on noop destroy */
	if (ok)
	{
		_seterr_reply(&reply_msg, &(cu->cu_error));
		if (cu->cu_error.re_status == RPC_SUCCESS)
		{
			if (!AUTH_VALIDATE(cl->cl_auth,
							   &reply_msg.acpted_rply.ar_verf))
			{
				cu->cu_error.re_status = RPC_AUTHERROR;
				cu->cu_error.re_why = AUTH_INVALIDRESP;
			}
			if (reply_msg.acpted_rply.ar_verf.oa_base != NULL)
			{
				xdrs->x_op = XDR_FREE;
				(void) xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf));
			}
		} /* end successful completion */
		else
		{
			/* maybe our credentials need to be refreshed ... */
			if (nrefreshes > 0 && AUTH_REFRESH(cl->cl_auth))
			{
				nrefreshes--;
				goto call_again;
			}
		} /* end of unsuccessful completion */
	} /* end of valid reply message */
	else
	{
		cu->cu_error.re_status = RPC_CANTDECODERES;
	}

	return (cu->cu_error.re_status);
}
static enum clnt_stat
clnt_vc_call(
	CLIENT *h,
	rpcproc_t proc,
	xdrproc_t xdr_args,
	const char *args_ptr,
	xdrproc_t xdr_results,
	caddr_t results_ptr,
	struct timeval timeout
)
{
	struct ct_data *ct;
	XDR *xdrs;
	struct rpc_msg reply_msg;
	u_int32_t x_id;
	u_int32_t *msg_x_id;
	bool_t shipnow;
	int refreshes = 2;
#ifdef _REENTRANT
	sigset_t mask, newmask;
#endif

	_DIAGASSERT(h != NULL);

	ct = (struct ct_data *) h->cl_private;

#ifdef _REENTRANT
	__clnt_sigfillset(&newmask);
	thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
	mutex_lock(&clnt_fd_lock);
	while (vc_fd_locks[ct->ct_fd])
		cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
	vc_fd_locks[ct->ct_fd] = __rpc_lock_value;
	mutex_unlock(&clnt_fd_lock);
#endif

	xdrs = &(ct->ct_xdrs);
	msg_x_id = &ct->ct_u.ct_mcalli;

	if (!ct->ct_waitset) {
		if (time_not_ok(&timeout) == FALSE)
		ct->ct_wait = timeout;
	}

	shipnow =
	    (xdr_results == NULL && timeout.tv_sec == 0
	    && timeout.tv_usec == 0) ? FALSE : TRUE;

call_again:
	xdrs->x_op = XDR_ENCODE;
	ct->ct_error.re_status = RPC_SUCCESS;
	x_id = ntohl(--(*msg_x_id));
	if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) ||
	    (! XDR_PUTINT32(xdrs, (int32_t *)&proc)) ||
	    (! AUTH_MARSHALL(h->cl_auth, xdrs)) ||
	    (! (*xdr_args)(xdrs, __UNCONST(args_ptr)))) {
		if (ct->ct_error.re_status == RPC_SUCCESS)
			ct->ct_error.re_status = RPC_CANTENCODEARGS;
		(void)xdrrec_endofrecord(xdrs, TRUE);
		release_fd_lock(ct->ct_fd, mask);
		return (ct->ct_error.re_status);
	}
	if (! xdrrec_endofrecord(xdrs, shipnow)) {
		release_fd_lock(ct->ct_fd, mask);
		return (ct->ct_error.re_status = RPC_CANTSEND);
	}
	if (! shipnow) {
		release_fd_lock(ct->ct_fd, mask);
		return (RPC_SUCCESS);
	}
	/*
	 * Hack to provide rpc-based message passing
	 */
	if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
		release_fd_lock(ct->ct_fd, mask);
		return(ct->ct_error.re_status = RPC_TIMEDOUT);
	}


	/*
	 * Keep receiving until we get a valid transaction id
	 */
	xdrs->x_op = XDR_DECODE;
	for (;;) {
		reply_msg.acpted_rply.ar_verf = _null_auth;
		reply_msg.acpted_rply.ar_results.where = NULL;
		reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
		if (! xdrrec_skiprecord(xdrs)) {
			release_fd_lock(ct->ct_fd, mask);
			return (ct->ct_error.re_status);
		}
		/* now decode and validate the response header */
		if (! xdr_replymsg(xdrs, &reply_msg)) {
			if (ct->ct_error.re_status == RPC_SUCCESS)
				continue;
			release_fd_lock(ct->ct_fd, mask);
			return (ct->ct_error.re_status);
		}
		if (reply_msg.rm_xid == x_id)
			break;
	}

	/*
	 * process header
	 */
	_seterr_reply(&reply_msg, &(ct->ct_error));
	if (ct->ct_error.re_status == RPC_SUCCESS) {
		if (! AUTH_VALIDATE(h->cl_auth,
		    &reply_msg.acpted_rply.ar_verf)) {
			ct->ct_error.re_status = RPC_AUTHERROR;
			ct->ct_error.re_why = AUTH_INVALIDRESP;
		} else if (! (*xdr_results)(xdrs, results_ptr)) {
			if (ct->ct_error.re_status == RPC_SUCCESS)
				ct->ct_error.re_status = RPC_CANTDECODERES;
		}
		/* free verifier ... */
		if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
			xdrs->x_op = XDR_FREE;
			(void)xdr_opaque_auth(xdrs,
			    &(reply_msg.acpted_rply.ar_verf));
		}
	}  /* end successful completion */
	else {
		/* maybe our credentials need to be refreshed ... */
		if (refreshes-- && AUTH_REFRESH(h->cl_auth))
			goto call_again;
	}  /* end of unsuccessful completion */
	release_fd_lock(ct->ct_fd, mask);
	return (ct->ct_error.re_status);
}
Exemple #7
0
static enum clnt_stat 
clntudp_call(
	register CLIENT	*cl,		/* client handle */
	unsigned long	proc,		/* procedure number */
	xdrproc_t	xargs,		/* xdr routine for args */
	char*		argsp,		/* pointer to args */
	xdrproc_t	xresults,	/* xdr routine for results */
	char*		resultsp,	/* pointer to results */
	struct timeval	utimeout)	/* seconds to wait before giving up */
{
	register struct cu_data *cu = (struct cu_data *)cl->cl_private;
	register XDR *xdrs;
	register int outlen;
	register ssize_t inlen;
	socklen_t fromlen;
#ifdef FD_SETSIZE
	fd_set readfds;
	fd_set mask;
#else
	int readfds;
	register int mask;
#endif /* def FD_SETSIZE */
	struct sockaddr_in from;
	struct rpc_msg reply_msg;
	XDR reply_xdrs;
	struct timeval time_waited;
	bool_t ok;
	int nrefreshes = 2;	/* number of times to refresh cred */
	struct timeval timeout;

	if (cu->cu_total.tv_usec == -1) {
		timeout = utimeout;     /* use supplied timeout */
	} else {
		timeout = cu->cu_total; /* use default timeout */
	}

	time_waited.tv_sec = 0;
	time_waited.tv_usec = 0;
call_again:
	xdrs = &(cu->cu_outxdrs);
	xdrs->x_op = XDR_ENCODE;
	XDR_SETPOS(xdrs, cu->cu_xdrpos);
	/*
	 * the transaction is the first thing in the out buffer
	 */
	(*(uint32_t*)(cu->cu_outbuf))++;
	if ((! xdr_u_long(xdrs, &proc)) ||
	    (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
	    (! (*xargs)(xdrs, argsp)))
		return (cu->cu_error.re_status = RPC_CANTENCODEARGS);
	outlen = (int)XDR_GETPOS(xdrs);

send_again:
	if (sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0,
	    (struct sockaddr *)&(cu->cu_raddr), cu->cu_rlen)
	    != (ssize_t)outlen) {
		cu->cu_error.re_errno = errno;
		return (cu->cu_error.re_status = RPC_CANTSEND);
	}

	/*
	 * Hack to provide rpc-based message passing
	 */
	if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
		return (cu->cu_error.re_status = RPC_TIMEDOUT);
	}
	/*
	 * sub-optimal code appears here because we have
	 * some clock time to spare while the packets are in flight.
	 * (We assume that this is actually only executed once.)
	 */
	reply_msg.acpted_rply.ar_verf = _null_auth;
	reply_msg.acpted_rply.ar_results.where = resultsp;
	reply_msg.acpted_rply.ar_results.proc = xresults;
#ifdef FD_SETSIZE
	FD_ZERO(&mask);
	FD_SET(cu->cu_sock, &mask);
#else
	mask = 1 << cu->cu_sock;
#endif /* def FD_SETSIZE */
	for (;;) {
		struct timeval	to = cu->cu_wait;

		readfds = mask;
		switch (select(cu->cu_sock+1, &readfds, NULL, 
			       NULL, &to)) {

		case 0:
			time_waited.tv_sec += cu->cu_wait.tv_sec;
			time_waited.tv_usec += cu->cu_wait.tv_usec;
			while (time_waited.tv_usec >= 1000000) {
				time_waited.tv_sec++;
				time_waited.tv_usec -= 1000000;
			}
			if ((time_waited.tv_sec < timeout.tv_sec) ||
				((time_waited.tv_sec == timeout.tv_sec) &&
				(time_waited.tv_usec < timeout.tv_usec)))
				goto send_again;	
			return (cu->cu_error.re_status = RPC_TIMEDOUT);

		/*
		 * buggy in other cases because time_waited is not being
		 * updated.
		 */
		case -1:
			if (errno == EINTR)
				continue;	
			cu->cu_error.re_errno = errno;
			return (cu->cu_error.re_status = RPC_CANTRECV);
		}
		do {
			fromlen = (socklen_t)sizeof(struct sockaddr);
			inlen = recvfrom(cu->cu_sock, cu->cu_inbuf, 
				(int) cu->cu_recvsz, 0,
				(struct sockaddr *)&from, &fromlen);
		} while (inlen < 0 && errno == EINTR);
		if (inlen < 0) {
			if (errno == EWOULDBLOCK)
				continue;	
			cu->cu_error.re_errno = errno;
			return (cu->cu_error.re_status = RPC_CANTRECV);
		}
		if (inlen < sizeof(uint32_t))
			continue;	

		/* see if reply transaction id matches sent id */
		if (*(uint32_t*)cu->cu_inbuf != *(uint32_t*)cu->cu_outbuf)
			continue;	

		/* we now assume we have the proper reply */
		break;
	}

	/*
	 * now decode and validate the response
	 */
	xdrmem_create(&reply_xdrs, cu->cu_inbuf, (unsigned)inlen, 
	    XDR_DECODE);
	ok = xdr_replymsg(&reply_xdrs, &reply_msg);
	/* XDR_DESTROY(&reply_xdrs);  save a few cycles on noop destroy */
	if (ok) {
		_seterr_reply(&reply_msg, &(cu->cu_error));
		if (cu->cu_error.re_status == RPC_SUCCESS) {
			if (! AUTH_VALIDATE(cl->cl_auth,
				reply_msg.acpted_rply.ar_verf)) {
				cu->cu_error.re_status = RPC_AUTHERROR;
				cu->cu_error.re_why = AUTH_INVALIDRESP;
			}
			if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
				xdrs->x_op = XDR_FREE;
				(void)xdr_opaque_auth(xdrs,
				    &(reply_msg.acpted_rply.ar_verf));
			} 
		}  /* end successful completion */
		else {
			/* maybe our credentials need to be refreshed ... */
			if (nrefreshes > 0 && AUTH_REFRESH(cl->cl_auth)) {
				nrefreshes--;
				goto call_again;
			}
		}  /* end of unsuccessful completion */
	}  /* end of valid reply message */
	else {
		cu->cu_error.re_status = RPC_CANTDECODERES;
	}
	return (cu->cu_error.re_status);
}
static enum clnt_stat
clntudp_call (
     CLIENT *cl,	/* client handle */
     u_long proc,		/* procedure number */
     xdrproc_t xargs,		/* xdr routine for args */
     caddr_t argsp,		/* pointer to args */
     xdrproc_t xresults,	/* xdr routine for results */
     caddr_t resultsp,		/* pointer to results */
     struct timeval utimeout	/* seconds to wait before giving up */)
{
  struct cu_data *cu = (struct cu_data *) cl->cl_private;
  XDR *xdrs;
  int outlen = 0;
  int inlen;
  socklen_t fromlen;
  struct pollfd fd;
  int milliseconds = (cu->cu_wait.tv_sec * 1000) +
    (cu->cu_wait.tv_usec / 1000);
  struct sockaddr_in from;
  struct rpc_msg reply_msg;
  XDR reply_xdrs;
  struct timeval time_waited;
  bool_t ok;
  int nrefreshes = 2;		/* number of times to refresh cred */
  struct timeval timeout;
  int anyup;			/* any network interface up */

  if (cu->cu_total.tv_usec == -1)
    {
      timeout = utimeout;	/* use supplied timeout */
    }
  else
    {
      timeout = cu->cu_total;	/* use default timeout */
    }

  time_waited.tv_sec = 0;
  time_waited.tv_usec = 0;
call_again:
  xdrs = &(cu->cu_outxdrs);
  if (xargs == NULL)
    goto get_reply;
  xdrs->x_op = XDR_ENCODE;
  XDR_SETPOS (xdrs, cu->cu_xdrpos);
  /*
   * the transaction is the first thing in the out buffer
   */
  (*(uint32_t *) (cu->cu_outbuf))++;
  if ((!XDR_PUTLONG (xdrs, (long *) &proc)) ||
      (!AUTH_MARSHALL (cl->cl_auth, xdrs)) ||
      (!(*xargs) (xdrs, argsp)))
    return (cu->cu_error.re_status = RPC_CANTENCODEARGS);
  outlen = (int) XDR_GETPOS (xdrs);

send_again:
  if (sendto (cu->cu_sock, cu->cu_outbuf, outlen, 0,
	      (struct sockaddr *) &(cu->cu_raddr), cu->cu_rlen)
      != outlen)
    {
      cu->cu_error.re_errno = errno;
      return (cu->cu_error.re_status = RPC_CANTSEND);
    }

  /*
   * Hack to provide rpc-based message passing
   */
  if (timeout.tv_sec == 0 && timeout.tv_usec == 0)
    {
      return (cu->cu_error.re_status = RPC_TIMEDOUT);
    }
 get_reply:
  /*
   * sub-optimal code appears here because we have
   * some clock time to spare while the packets are in flight.
   * (We assume that this is actually only executed once.)
   */
  reply_msg.acpted_rply.ar_verf = _null_auth;
  reply_msg.acpted_rply.ar_results.where = resultsp;
  reply_msg.acpted_rply.ar_results.proc = xresults;
  fd.fd = cu->cu_sock;
  fd.events = POLLIN;
  anyup = 0;
  for (;;)
    {
      switch (poll (&fd, 1, milliseconds))
	{

	case 0:
	  if (anyup == 0)
	    {
	      anyup = is_network_up (cu->cu_sock);
	      if (!anyup)
		return (cu->cu_error.re_status = RPC_CANTRECV);
	    }

	  time_waited.tv_sec += cu->cu_wait.tv_sec;
	  time_waited.tv_usec += cu->cu_wait.tv_usec;
	  while (time_waited.tv_usec >= 1000000)
	    {
	      time_waited.tv_sec++;
	      time_waited.tv_usec -= 1000000;
	    }
	  if ((time_waited.tv_sec < timeout.tv_sec) ||
	      ((time_waited.tv_sec == timeout.tv_sec) &&
	       (time_waited.tv_usec < timeout.tv_usec)))
	    goto send_again;
	  return (cu->cu_error.re_status = RPC_TIMEDOUT);

	  /*
	   * buggy in other cases because time_waited is not being
	   * updated.
	   */
	case -1:
	  if (errno == EINTR)
	    continue;
	  cu->cu_error.re_errno = errno;
	  return (cu->cu_error.re_status = RPC_CANTRECV);
	}
#ifdef IP_RECVERR
      if (fd.revents & POLLERR)
	{
	  struct msghdr msg;
	  struct cmsghdr *cmsg;
	  struct sock_extended_err *e;
	  struct sockaddr_in err_addr;
	  struct iovec iov;
	  char *cbuf = (char *) alloca (outlen + 256);
	  int ret;

	  iov.iov_base = cbuf + 256;
	  iov.iov_len = outlen;
	  msg.msg_name = (void *) &err_addr;
	  msg.msg_namelen = sizeof (err_addr);
	  msg.msg_iov = &iov;
	  msg.msg_iovlen = 1;
	  msg.msg_flags = 0;
	  msg.msg_control = cbuf;
	  msg.msg_controllen = 256;
	  ret = recvmsg (cu->cu_sock, &msg, MSG_ERRQUEUE);
	  if (ret >= 0
	      && memcmp (cbuf + 256, cu->cu_outbuf, ret) == 0
	      && (msg.msg_flags & MSG_ERRQUEUE)
	      && ((msg.msg_namelen == 0
		   && ret >= 12)
		  || (msg.msg_namelen == sizeof (err_addr)
		      && err_addr.sin_family == AF_INET
		      && memcmp (&err_addr.sin_addr, &cu->cu_raddr.sin_addr,
				 sizeof (err_addr.sin_addr)) == 0
		      && err_addr.sin_port == cu->cu_raddr.sin_port)))
	    for (cmsg = CMSG_FIRSTHDR (&msg); cmsg;
		 cmsg = CMSG_NXTHDR (&msg, cmsg))
	      if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR)
		{
		  e = (struct sock_extended_err *) CMSG_DATA(cmsg);
		  cu->cu_error.re_errno = e->ee_errno;
		  return (cu->cu_error.re_status = RPC_CANTRECV);
		}
	}
#endif
      do
	{
	  fromlen = sizeof (struct sockaddr);
	  inlen = recvfrom (cu->cu_sock, cu->cu_inbuf,
			    (int) cu->cu_recvsz, 0,
			    (struct sockaddr *) &from, &fromlen);
	}
      while (inlen < 0 && errno == EINTR);
      if (inlen < 0)
	{
	  if (errno == EWOULDBLOCK)
	    continue;
	  cu->cu_error.re_errno = errno;
	  return (cu->cu_error.re_status = RPC_CANTRECV);
	}
      if (inlen < 4)
	continue;

      /* see if reply transaction id matches sent id.
        Don't do this if we only wait for a replay */
      if (xargs != NULL
	  && (*((u_int32_t *) (cu->cu_inbuf))
	      != *((u_int32_t *) (cu->cu_outbuf))))
	continue;
      /* we now assume we have the proper reply */
      break;
    }

  /*
   * now decode and validate the response
   */
  xdrmem_create (&reply_xdrs, cu->cu_inbuf, (u_int) inlen, XDR_DECODE);
  ok = xdr_replymsg (&reply_xdrs, &reply_msg);
  /* XDR_DESTROY(&reply_xdrs);  save a few cycles on noop destroy */
  if (ok)
    {
      _seterr_reply (&reply_msg, &(cu->cu_error));
      if (cu->cu_error.re_status == RPC_SUCCESS)
	{
	  if (!AUTH_VALIDATE (cl->cl_auth,
			      &reply_msg.acpted_rply.ar_verf))
	    {
	      cu->cu_error.re_status = RPC_AUTHERROR;
	      cu->cu_error.re_why = AUTH_INVALIDRESP;
	    }
	  if (reply_msg.acpted_rply.ar_verf.oa_base != NULL)
	    {
	      xdrs->x_op = XDR_FREE;
	      (void) xdr_opaque_auth (xdrs,
				      &(reply_msg.acpted_rply.ar_verf));
	    }
	}			/* end successful completion */
      else
	{
	  /* maybe our credentials need to be refreshed ... */
	  if (nrefreshes > 0 && AUTH_REFRESH (cl->cl_auth))
	    {
	      nrefreshes--;
	      goto call_again;
	    }
	}			/* end of unsuccessful completion */
    }				/* end of valid reply message */
  else
    {
      cu->cu_error.re_status = RPC_CANTDECODERES;
    }
  return cu->cu_error.re_status;
}
Exemple #9
0
static enum clnt_stat
clnt_dg_call(CLIENT *clnt,	/* client handle */
	     AUTH *auth,	/* auth handle */
	     rpcproc_t proc,	/* procedure number */
	     xdrproc_t xargs,	/* xdr routine for args */
	     void *argsp,	/* pointer to args */
	     xdrproc_t xresults,	/* xdr routine for results */
	     void *resultsp,	/* pointer to results */
	     struct timeval utimeout
	     /* seconds to wait before giving up */)
{
	struct cu_data *cu = CU_DATA((struct cx_data *)clnt->cl_p1);
	XDR *xdrs;
	size_t outlen = 0;
	struct rpc_msg reply_msg;
	XDR reply_xdrs;
	bool ok;
	int nrefreshes = 2;	/* number of times to refresh cred */
	struct timeval timeout;
	struct pollfd fd;
	int total_time, nextsend_time, tv = 0;
	struct sockaddr *sa;
	socklen_t __attribute__ ((unused)) inlen, salen;
	ssize_t recvlen = 0;
	u_int32_t xid, inval, outval;
	bool slocked = false;
	bool rlocked = false;
	bool once = true;

	outlen = 0;
	rpc_dplx_slc(clnt);
	slocked = true;
	if (cu->cu_total.tv_usec == -1)
		timeout = utimeout;	/* use supplied timeout */
	else
		timeout = cu->cu_total;	/* use default timeout */
	total_time = timeout.tv_sec * 1000 + timeout.tv_usec / 1000;
	nextsend_time = cu->cu_wait.tv_sec * 1000 + cu->cu_wait.tv_usec / 1000;

	if (cu->cu_connect && !cu->cu_connected) {
		if (connect
		    (cu->cu_fd, (struct sockaddr *)&cu->cu_raddr,
		     cu->cu_rlen) < 0) {
			cu->cu_error.re_errno = errno;
			cu->cu_error.re_status = RPC_CANTSEND;
			goto out;
		}
		cu->cu_connected = 1;
	}
	if (cu->cu_connected) {
		sa = NULL;
		salen = 0;
	} else {
		sa = (struct sockaddr *)&cu->cu_raddr;
		salen = cu->cu_rlen;
	}

	/* Clean up in case the last call ended in a longjmp(3) call. */
 call_again:
	if (!slocked) {
		rpc_dplx_slc(clnt);
		slocked = true;
	}
	xdrs = &(cu->cu_outxdrs);
	if (cu->cu_async == true && xargs == NULL)
		goto get_reply;
	xdrs->x_op = XDR_ENCODE;
	XDR_SETPOS(xdrs, cu->cu_xdrpos);
	/*
	 * the transaction is the first thing in the out buffer
	 * XXX Yes, and it's in network byte order, so we should to
	 * be careful when we increment it, shouldn't we.
	 */
	xid = ntohl(*(u_int32_t *) (void *)(cu->cu_outbuf));
	xid++;
	*(u_int32_t *) (void *)(cu->cu_outbuf) = htonl(xid);

	if ((!XDR_PUTINT32(xdrs, (int32_t *) &proc))
	    || (!AUTH_MARSHALL(auth, xdrs))
	    || (!AUTH_WRAP(auth, xdrs, xargs, argsp))) {
		cu->cu_error.re_status = RPC_CANTENCODEARGS;
		goto out;
	}
	outlen = (size_t) XDR_GETPOS(xdrs);

 send_again:
	nextsend_time = cu->cu_wait.tv_sec * 1000 + cu->cu_wait.tv_usec / 1000;
	if (sendto(cu->cu_fd, cu->cu_outbuf, outlen, 0, sa, salen) != outlen) {
		cu->cu_error.re_errno = errno;
		cu->cu_error.re_status = RPC_CANTSEND;
		goto out;
	}

 get_reply:
	/*
	 * sub-optimal code appears here because we have
	 * some clock time to spare while the packets are in flight.
	 * (We assume that this is actually only executed once.)
	 */
	rpc_dplx_suc(clnt);
	slocked = false;

	rpc_dplx_rlc(clnt);
	rlocked = true;

	reply_msg.acpted_rply.ar_verf = _null_auth;
	reply_msg.acpted_rply.ar_results.where = NULL;
	reply_msg.acpted_rply.ar_results.proc = (xdrproc_t) xdr_void;

	fd.fd = cu->cu_fd;
	fd.events = POLLIN;
	fd.revents = 0;
	while ((total_time > 0) || once) {
		tv = total_time < nextsend_time ? total_time : nextsend_time;
		once = false;
		switch (poll(&fd, 1, tv)) {
		case 0:
			total_time -= tv;
			rpc_dplx_ruc(clnt);
			rlocked = false;
			if (total_time <= 0) {
				cu->cu_error.re_status = RPC_TIMEDOUT;
				goto out;
			}
			goto send_again;
		case -1:
			if (errno == EINTR)
				continue;
			cu->cu_error.re_status = RPC_CANTRECV;
			cu->cu_error.re_errno = errno;
			goto out;
		}
		break;
	}
#ifdef IP_RECVERR
	if (fd.revents & POLLERR) {
		struct msghdr msg;
		struct cmsghdr *cmsg;
		struct sock_extended_err *e;
		struct sockaddr_in err_addr;
		struct sockaddr_in *sin = (struct sockaddr_in *)&cu->cu_raddr;
		struct iovec iov;
		char *cbuf = (char *)alloca(outlen + 256);
		int ret;

		iov.iov_base = cbuf + 256;
		iov.iov_len = outlen;
		msg.msg_name = (void *)&err_addr;
		msg.msg_namelen = sizeof(err_addr);
		msg.msg_iov = &iov;
		msg.msg_iovlen = 1;
		msg.msg_flags = 0;
		msg.msg_control = cbuf;
		msg.msg_controllen = 256;
		ret = recvmsg(cu->cu_fd, &msg, MSG_ERRQUEUE);
		if (ret >= 0 && memcmp(cbuf + 256, cu->cu_outbuf, ret) == 0
		    && (msg.msg_flags & MSG_ERRQUEUE)
		    && ((msg.msg_namelen == 0 && ret >= 12)
			|| (msg.msg_namelen == sizeof(err_addr)
			    && err_addr.sin_family == AF_INET
			    && memcmp(&err_addr.sin_addr, &sin->sin_addr,
				      sizeof(err_addr.sin_addr)) == 0
			    && err_addr.sin_port == sin->sin_port)))
			for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
			     cmsg = CMSG_NXTHDR(&msg, cmsg))
				if ((cmsg->cmsg_level == SOL_IP)
				    && (cmsg->cmsg_type == IP_RECVERR)) {
					e = (struct sock_extended_err *)
					    CMSG_DATA(cmsg);
					cu->cu_error.re_errno = e->ee_errno;
					cu->cu_error.re_status = RPC_CANTRECV;
				}
	}
#endif

	/* We have some data now */
	do {
		recvlen =
		    recvfrom(cu->cu_fd, cu->cu_inbuf, cu->cu_recvsz, 0, NULL,
			     NULL);
	} while (recvlen < 0 && errno == EINTR);
	if (recvlen < 0 && errno != EWOULDBLOCK) {
		cu->cu_error.re_errno = errno;
		cu->cu_error.re_status = RPC_CANTRECV;
		goto out;
	}

	if (recvlen < sizeof(u_int32_t)) {
		total_time -= tv;
		rpc_dplx_ruc(clnt);
		rlocked = false;
		goto send_again;
	}

	if (cu->cu_async == true)
		inlen = (socklen_t) recvlen;
	else {
		memcpy(&inval, cu->cu_inbuf, sizeof(u_int32_t));
		memcpy(&outval, cu->cu_outbuf, sizeof(u_int32_t));
		if (inval != outval) {
			total_time -= tv;
			rpc_dplx_ruc(clnt);
			rlocked = false;
			goto send_again;
		}
		inlen = (socklen_t) recvlen;
	}

	/*
	 * now decode and validate the response
	 */

	xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int) recvlen, XDR_DECODE);
	ok = xdr_replymsg(&reply_xdrs, &reply_msg);
	/* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */
	if (ok) {
		if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED)
		    && (reply_msg.acpted_rply.ar_stat == SUCCESS))
			cu->cu_error.re_status = RPC_SUCCESS;
		else
			_seterr_reply(&reply_msg, &(cu->cu_error));

		if (cu->cu_error.re_status == RPC_SUCCESS) {
			if (!AUTH_VALIDATE
			    (auth, &reply_msg.acpted_rply.ar_verf)) {
				cu->cu_error.re_status = RPC_AUTHERROR;
				cu->cu_error.re_why = AUTH_INVALIDRESP;
			} else
			    if (!AUTH_UNWRAP
				(auth, &reply_xdrs, xresults, resultsp)) {
				if (cu->cu_error.re_status == RPC_SUCCESS)
					cu->cu_error.re_status =
					    RPC_CANTDECODERES;
			}
			if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
				xdrs->x_op = XDR_FREE;
				(void)xdr_opaque_auth(xdrs,
						      &(reply_msg.acpted_rply.
							ar_verf));
			}
		}
		/* end successful completion */
		/*
		 * If unsuccesful AND error is an authentication error
		 * then refresh credentials and try again, else break
		 */
		else if (cu->cu_error.re_status == RPC_AUTHERROR)
			/* maybe our credentials need to be refreshed ... */
			if (nrefreshes > 0 && AUTH_REFRESH(auth, &reply_msg)) {
				nrefreshes--;
				rpc_dplx_ruc(clnt);
				rlocked = false;
				goto call_again;
			}
		/* end of unsuccessful completion */
	} /* end of valid reply message */
	else
		cu->cu_error.re_status = RPC_CANTDECODERES;

out:
	if (slocked)
		rpc_dplx_suc(clnt);
	if (rlocked)
		rpc_dplx_ruc(clnt);

	return (cu->cu_error.re_status);
}
Exemple #10
0
/* ARGSUSED */
static enum clnt_stat
clnt_raw_call(CLIENT *h, AUTH *auth, rpcproc_t proc, xdrproc_t xargs,
              void *argsp, xdrproc_t xresults, void *resultsp,
              struct timeval timeout)
{
    struct clntraw_private *clp = clntraw_private;
    XDR *xdrs = &clp->xdr_stream;
    struct rpc_msg msg;
    enum clnt_stat status;
    struct rpc_err error;

    assert(h != NULL);

    mutex_lock(&clntraw_lock);
    if (clp == NULL) {
        mutex_unlock(&clntraw_lock);
        return (RPC_FAILED);
    }
    mutex_unlock(&clntraw_lock);

call_again:
    /*
     * send request
     */
    xdrs->x_op = XDR_ENCODE;
    XDR_SETPOS(xdrs, 0);
    clp->u.mashl_rpcmsg.rm_xid ++ ;
    if ((! XDR_PUTBYTES(xdrs, clp->u.mashl_callmsg, clp->mcnt)) ||
        (! XDR_PUTINT32(xdrs, (int32_t *)&proc)) ||
        (! AUTH_MARSHALL(auth, xdrs)) ||
        (! (*xargs)(xdrs, argsp))) {
        return (RPC_CANTENCODEARGS);
    }
    (void)XDR_GETPOS(xdrs);  /* called just to cause overhead */

    /*
     * We have to call server input routine here because this is
     * all going on in one process. Yuk.
     */
    svc_getreq_common(FD_SETSIZE);

    /*
     * get results
     */
    xdrs->x_op = XDR_DECODE;
    XDR_SETPOS(xdrs, 0);
    msg.acpted_rply.ar_verf = _null_auth;
    msg.acpted_rply.ar_results.where = resultsp;
    msg.acpted_rply.ar_results.proc = xresults;
    if (! xdr_replymsg(xdrs, &msg)) {
        /*
         * It's possible for xdr_replymsg() to fail partway
         * through its attempt to decode the result from the
         * server. If this happens, it will leave the reply
         * structure partially populated with dynamically
         * allocated memory. (This can happen if someone uses
         * clntudp_bufcreate() to create a CLIENT handle and
         * specifies a receive buffer size that is too small.)
         * This memory must be free()ed to avoid a leak.
         */
        int op = xdrs->x_op;
        xdrs->x_op = XDR_FREE;
        xdr_replymsg(xdrs, &msg);
        xdrs->x_op = op;
        return (RPC_CANTDECODERES);
    }
    _seterr_reply(&msg, &error);
    status = error.re_status;

    if (status == RPC_SUCCESS) {
        if (! AUTH_VALIDATE(auth, &msg.acpted_rply.ar_verf)) {
            status = RPC_AUTHERROR;
        }
    }  /* end successful completion */
    else {
        if (AUTH_REFRESH(auth, &msg))
            goto call_again;
    }  /* end of unsuccessful completion */

    if (status == RPC_SUCCESS) {
        if (! AUTH_VALIDATE(auth, &msg.acpted_rply.ar_verf)) {
            status = RPC_AUTHERROR;
        }
        if (msg.acpted_rply.ar_verf.oa_base != NULL) {
            xdrs->x_op = XDR_FREE;
            (void)xdr_opaque_auth(xdrs, &(msg.acpted_rply.ar_verf));
        }
    }

    return (status);
}
Exemple #11
0
static int
nd_get_reply(TIUSER *tiptr, XDR *xdrp, uint32_t call_xid, int *badmsg)
{
	static struct rpc_msg		reply_msg;
	static struct rpc_err		rpc_err;
	static struct nfsattrstat	na;
	static struct WRITE3res		wres;
	static struct t_kunitdata	rudata;
	int				uderr;
	int				type;
	int				error;

	*badmsg = 0;

	rudata.addr.maxlen = 0;
	rudata.opt.maxlen = 0;
	rudata.udata.udata_mp = (mblk_t *)NULL;

	nd_log("nfs_dump: calling t_krcvudata\n");

	if (error = t_krcvudata(tiptr, &rudata, &type, &uderr)) {
		if (error == EBADMSG) {
			cmn_err(CE_WARN, "\tnfs_dump:  received EBADMSG");
			*badmsg = 1;
			return (0);
		}
		nfs_perror(error, "\nnfs_dump: t_krcvudata failed: %m\n");
		return (EIO);
	}
	if (type != T_DATA) {
		cmn_err(CE_WARN, "\tnfs_dump:  received type %d", type);
		*badmsg = 1;
		return (0);
	}
	if (!rudata.udata.udata_mp) {
		cmn_err(CE_WARN, "\tnfs_dump: null receive");
		*badmsg = 1;
		return (0);
	}

	/*
	 * Decode results.
	 */
	xdrmblk_init(xdrp, rudata.udata.udata_mp, XDR_DECODE, 0);

	reply_msg.acpted_rply.ar_verf = _null_auth;
	switch (nfsdump_version) {
	case NFS_VERSION:
		reply_msg.acpted_rply.ar_results.where = (caddr_t)&na;
		reply_msg.acpted_rply.ar_results.proc = xdr_attrstat;
		break;
	case NFS_V3:
		reply_msg.acpted_rply.ar_results.where = (caddr_t)&wres;
		reply_msg.acpted_rply.ar_results.proc = xdr_WRITE3res;
		break;
	default:
		XDR_DESTROY(xdrp);
		return (EIO);
	}

	if (!xdr_replymsg(xdrp, &reply_msg)) {
		XDR_DESTROY(xdrp);
		cmn_err(CE_WARN, "\tnfs_dump: xdr_replymsg failed");
		return (EIO);
	}

	if (reply_msg.rm_xid != call_xid) {
		XDR_DESTROY(xdrp);
		*badmsg = 1;
		return (0);
	}

	_seterr_reply(&reply_msg, &rpc_err);

	if (rpc_err.re_status != RPC_SUCCESS) {
		XDR_DESTROY(xdrp);
		cmn_err(CE_WARN, "\tnfs_dump: RPC error %d (%s)",
		    rpc_err.re_status, clnt_sperrno(rpc_err.re_status));
		return (EIO);
	}

	switch (nfsdump_version) {
	case NFS_VERSION:
		if (na.ns_status) {
			XDR_DESTROY(xdrp);
			cmn_err(CE_WARN, "\tnfs_dump: status %d", na.ns_status);
			return (EIO);
		}
		break;
	case NFS_V3:
		if (wres.status != NFS3_OK) {
			XDR_DESTROY(xdrp);
			cmn_err(CE_WARN, "\tnfs_dump: status %d", wres.status);
			return (EIO);
		}
		break;
	default:
		XDR_DESTROY(xdrp);
		return (EIO);
	}

	if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
		/* free auth handle */
		xdrp->x_op = XDR_FREE;
		(void) xdr_opaque_auth(xdrp, &(reply_msg.acpted_rply.ar_verf));
	}

	XDR_DESTROY(xdrp);

	freemsg(rudata.udata.udata_mp);

	return (0);
}
Exemple #12
0
static enum clnt_stat
clnt_rdma_call(CLIENT *cl,		/* client handle */
	       AUTH *auth,
	       rpcproc_t proc,		/* procedure number */
	       xdrproc_t xargs,		/* xdr routine for args */
	       void *argsp,		/* pointer to args */
	       xdrproc_t xresults,	/* xdr routine for results */
	       void *resultsp,		/* pointer to results */
	       struct timeval utimeout	/* seconds to wait before giving up */)
{
	struct cm_data *cm = CM_DATA((struct cx_data *) cl->cl_p1);
	XDR *xdrs;
	struct rpc_msg reply_msg;
	bool ok;
#if 0
	struct timeval timeout;
	int total_time;
#endif
//	sigset_t mask;
	socklen_t  __attribute__((unused)) inlen, salen;
	int nrefreshes = 2;		/* number of times to refresh cred */

//	thr_sigsetmask(SIG_SETMASK, (sigset_t *) 0, &mask); /* XXX */
//	vc_fd_lock_c(cl, &mask); //What does that do?
#if 0
	if (cm->cm_total.tv_usec == -1) {
		timeout = utimeout;	/* use supplied timeout */
	} else {
		timeout = cm->cm_total;	/* use default timeout */
	}
	total_time = timeout.tv_sec * 1000 + timeout.tv_usec / 1000;
#endif

	/* Clean up in case the last call ended in a longjmp(3) call. */
call_again:
	xdrs = &(cm->cm_xdrs);

	if (0) //FIXME check for async
		goto get_reply;

	if (! xdr_rdma_clnt_call(&cm->cm_xdrs, cm->call_msg.rm_xid) ||
	    ! xdr_callhdr(&(cm->cm_xdrs), &cm->call_msg)) {
		rpc_createerr.cf_stat = RPC_CANTENCODEARGS;  /* XXX */
		rpc_createerr.cf_error.re_errno = 0;
		goto out;
	}

	if ((! XDR_PUTINT32(xdrs, (int32_t *)&proc)) ||
	    (! AUTH_MARSHALL(auth, xdrs)) ||
	    (! AUTH_WRAP(auth, xdrs, xargs, argsp))) {
		cm->cm_error.re_status = RPC_CANTENCODEARGS;
		goto out;
	}

	if (! xdr_rdma_clnt_flushout(&cm->cm_xdrs)) {
		cm->cm_error.re_errno = errno;
		cm->cm_error.re_status = RPC_CANTSEND;
		goto out;
	}

get_reply:

	/*
	 * sub-optimal code appears here because we have
	 * some clock time to spare while the packets are in flight.
	 * (We assume that this is actually only executed once.)
	 */
	reply_msg.acpted_rply.ar_verf = _null_auth;
	reply_msg.acpted_rply.ar_results.where = NULL;
	reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;

	if (! xdr_rdma_clnt_reply(&cm->cm_xdrs, cm->call_msg.rm_xid)) {
		//FIXME add timeout
		cm->cm_error.re_status = RPC_TIMEDOUT;
		goto out;
	}

	/*
	 * now decode and validate the response
	 */

	ok = xdr_replymsg(&cm->cm_xdrs, &reply_msg);
	if (ok) {
		if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
			(reply_msg.acpted_rply.ar_stat == SUCCESS))
			cm->cm_error.re_status = RPC_SUCCESS;
		else
			_seterr_reply(&reply_msg, &(cm->cm_error));

		if (cm->cm_error.re_status == RPC_SUCCESS) {
			if (! AUTH_VALIDATE(auth,
					    &reply_msg.acpted_rply.ar_verf)) {
				cm->cm_error.re_status = RPC_AUTHERROR;
				cm->cm_error.re_why = AUTH_INVALIDRESP;
			} else if (! AUTH_UNWRAP(auth, &cm->cm_xdrs,
						 xresults, resultsp)) {
				if (cm->cm_error.re_status == RPC_SUCCESS)
				     cm->cm_error.re_status = RPC_CANTDECODERES;
			}
			if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
				xdrs->x_op = XDR_FREE;
				(void) xdr_opaque_auth(xdrs,
					&(reply_msg.acpted_rply.ar_verf));
			}
		}		/* end successful completion */
		/*
		 * If unsuccesful AND error is an authentication error
		 * then refresh credentials and try again, else break
		 */
		else if (cm->cm_error.re_status == RPC_AUTHERROR)
			/* maybe our credentials need to be refreshed ... */
			if (nrefreshes > 0 &&
			    AUTH_REFRESH(auth, &reply_msg)) {
				nrefreshes--;
				goto call_again;
			}
		/* end of unsuccessful completion */
	}	/* end of valid reply message */
	else {
		cm->cm_error.re_status = RPC_CANTDECODERES;

	}
out:
	cm->call_msg.rm_xid++;

//	vc_fd_unlock_c(cl, &mask);
	return (cm->cm_error.re_status);
}
Exemple #13
0
/*
 * our version of brpc_call(). We cache in portnumber in to->sin_port for
 * your convenience. to and from addresses are taken and received in network
 * order.
 */
enum clnt_stat
brpc_call(
	rpcprog_t	prog,		/* rpc program number to call. */
	rpcvers_t	vers,		/* rpc program version */
	rpcproc_t	proc,		/* rpc procedure to call */
	xdrproc_t	in_xdr,		/* routine to serialize arguments */
	caddr_t		args,		/* arg vector for remote call */
	xdrproc_t	out_xdr,	/* routine to deserialize results */
	caddr_t		ret,		/* addr of buf to place results in */
	int		rexmit,		/* retransmission interval (secs) */
	int		wait_time,	/* how long (secs) to wait (resp) */
	struct sockaddr_in 	*to,		/* destination */
	struct sockaddr_in	*from_who,	/* responder's port/address */
	uint_t			auth)		/* type of auth wanted. */
{
	int s;
	char hostname[MAXHOSTNAMELEN];
	struct sockaddr_in from;	/* us. */
	socklen_t from_len;
	XDR xmit_xdrs, rcv_xdrs;	/* xdr memory */
	AUTH *xmit_auth;		/* our chosen auth cookie */
	gid_t fake_gids = 1;		/* fake gids list for auth_unix */
	caddr_t trm_msg, rcv_msg;	/* outgoing/incoming rpc mesgs */
	struct rpc_msg reply;		/* our reply msg header */
	int trm_len, rcv_len;
	struct rpc_err rpc_error;	/* to store RPC errors in on rcv. */
	static uint_t xid;		/* current xid */
	uint_t xmit_len;		/* How much of the buffer we used */
	int nrefreshes = 2;		/* # of times to refresh cred */
	int flags = 0;			/* send flags */
	uint_t xdelay;
	int errors, preserve_errno;
	uint32_t timeout;
	socklen_t optlen;

	xmit_auth = NULL;

	trm_len = mac_get_mtu();
	trm_msg = bkmem_alloc(trm_len);
	rcv_msg = bkmem_alloc(NFSBUF_SIZE);

	if (trm_msg == NULL || rcv_msg == NULL) {
		errno = ENOMEM;
		rpc_error.re_status = RPC_CANTSEND;
		goto gt_error;
	}

	if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
		rpc_error.re_status = RPC_CANTSEND;
		goto gt_error;
	}

	if (dontroute) {
		(void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
		    (const void *)&dontroute, sizeof (dontroute));
	}

	if (to->sin_addr.s_addr == cached_destination.s_addr) {
		optlen = sizeof (timeout);
		(void) getsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (void *)&timeout,
		    &optlen);
	} else {
		cached_destination.s_addr = htonl(INADDR_ANY);
	}

	/* Bind our endpoint. */
	from.sin_family = AF_INET;
	ipv4_getipaddr(&from.sin_addr);
	from.sin_addr.s_addr = htonl(from.sin_addr.s_addr);
	from.sin_port = get_source_port(B_TRUE);

	if (bind(s, (struct sockaddr *)&from, sizeof (from)) < 0) {
		rpc_error.re_status = RPC_CANTSEND;
		goto gt_error;
	}

	bzero((caddr_t)&rpc_error, sizeof (struct rpc_err));

	/* initialize reply's rpc_msg struct, so we can decode later. */
	reply.acpted_rply.ar_verf = _null_auth;	/* struct copy */
	reply.acpted_rply.ar_results.where = ret;
	reply.acpted_rply.ar_results.proc = out_xdr;

	if (ntohs(to->sin_port) == 0) {
		/* snag the udp port we need. */
		if ((to->sin_port = (in_port_t)bpmap_getport(prog, vers,
		    &(rpc_error.re_status), to, NULL)) == 0)
			goto gt_error;
		to->sin_port = htons(to->sin_port);
	}

	/* generate xid - increment */
	if (xid == 0)
		xid = (uint_t)(prom_gettime() / 1000) + 1;
	else
		xid++;

	/* set up outgoing pkt as xdr modified. */
	xdrmem_create(&xmit_xdrs, trm_msg, trm_len, XDR_ENCODE);

	/* setup rpc header */
	if (rpc_hdr(&xmit_xdrs, xid, prog, vers, proc) != TRUE) {
		dprintf("brpc_call: cannot setup rpc header.\n");
		rpc_error.re_status = RPC_FAILED;
		goto gt_error;
	}

	/* setup authentication */
	switch (auth) {
	case AUTH_NONE:
		xmit_auth = authnone_create();
		break;
	case AUTH_UNIX:
		/*
		 * Assumes we've configured the stack and thus know our
		 * IP address/hostname, either by using DHCP or rarp/bootparams.
		 */
		gethostname(hostname, sizeof (hostname));
		xmit_auth = authunix_create(hostname, 0, 1, 1, &fake_gids);
		break;
	default:
		dprintf("brpc_call: Unsupported authentication type: %d\n",
		    auth);
		rpc_error.re_status = RPC_AUTHERROR;
		goto gt_error;
	/*NOTREACHED*/
	}

	/*
	 * rpc_hdr puts everything in the xmit buffer for the header
	 * EXCEPT the proc. Put it, and our authentication info into
	 * it now, serializing as we go. We will be at the place where
	 * we left off.
	 */
	xmit_xdrs.x_op = XDR_ENCODE;
	if ((XDR_PUTINT32(&xmit_xdrs, (int32_t *)&proc) == FALSE) ||
	    (AUTH_MARSHALL(xmit_auth, &xmit_xdrs, NULL) == FALSE) ||
	    ((*in_xdr)(&xmit_xdrs, args) == FALSE)) {
		rpc_error.re_status = RPC_CANTENCODEARGS;
		goto gt_error;
	} else
		xmit_len = (int)XDR_GETPOS(&xmit_xdrs); /* for sendto */

	/*
	 * Right now the outgoing packet should be all serialized and
	 * ready to go... Set up timers.
	 */

	xdelay = (rexmit == 0) ? RPC_REXMIT_MSEC : (rexmit * 1000);
	(void) setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (void *)&xdelay,
	    sizeof (xdelay));
	wait_time = (wait_time == 0) ? RPC_RCVWAIT_MSEC : (wait_time * 1000);

	wait_time += prom_gettime();

	/*
	 * send out the request. The first item in the receive buffer will
	 * be the xid. Check if it is correct.
	 */
	errors = 0;
	rpc_error.re_status = RPC_TIMEDOUT;
	do {
		if (sendto(s, trm_msg, xmit_len, flags, (struct sockaddr *)to,
		    sizeof (struct sockaddr_in)) < 0) {
			/*
			 * If errno is set to ETIMEDOUT, return
			 * with RPC status as RPC_TIMEDOUT. Calling
			 * funciton will take care of this error by
			 * retrying the RPC call.
			 */
			if (errno == ETIMEDOUT) {
				rpc_error.re_status = RPC_TIMEDOUT;
			} else {
				rpc_error.re_status = RPC_CANTSEND;
			}
			goto gt_error;
		}

		from_len = sizeof (struct sockaddr_in);
		while ((rcv_len = recvfrom(s, rcv_msg, NFSBUF_SIZE,
		    MSG_DONTWAIT, (struct sockaddr *)from_who,
		    &from_len)) > 0 || errors < RPC_ALLOWABLE_ERRORS) {
			if (rcv_len < 0) {
				if (errno == EWOULDBLOCK ||
				    errno == ETIMEDOUT) {
					break; /* timeout */
				}
				rpc_error.re_status = RPC_CANTRECV;
				goto gt_error;
			}
			if (ntohl(*((uint32_t *)(rcv_msg))) != xid) {
				dprintf("brpc_call: xid: 0x%x != 0x%x\n",
				    *(uint32_t *)(rcv_msg), xid);
				continue;
			}
			/*
			 * Let's deserialize the data into our 'ret' buffer.
			 */
			xdrmem_create(&rcv_xdrs, rcv_msg, rcv_len, XDR_DECODE);
			if (xdr_replymsg(&rcv_xdrs, &reply) == FALSE) {
				rpc_error.re_status = RPC_CANTDECODERES;
				goto gt_error;
			}
			_seterr_reply(&reply, &rpc_error);
			switch (rpc_error.re_status) {
			case RPC_SUCCESS:
				/*
				 * XXX - validate for unix and none
				 * always return true.
				 */
				if (AUTH_VALIDATE(xmit_auth,
				    &reply.acpted_rply.ar_verf) == FALSE) {
					rpc_error.re_status = RPC_AUTHERROR;
					rpc_error.re_why = AUTH_INVALIDRESP;
					errors++;
				}
				if (reply.acpted_rply.ar_verf.oa_base !=
				    0) {
					xmit_xdrs.x_op = XDR_FREE;
					(void) xdr_opaque_auth(
					    &xmit_xdrs,
					    &reply.acpted_rply.ar_verf);
				}
				break;

			case RPC_AUTHERROR:
				/*
				 * Let's see if our credentials need
				 * refreshing
				 */
				if (nrefreshes > 0 && AUTH_REFRESH(xmit_auth,
				    NULL, NULL)) {
					nrefreshes--;
				}
				errors++;
				break;

			case RPC_PROCUNAVAIL:
				/*
				 * Might be a silly portmapper implementation
				 * erroneously responding to our rpc broadcast
				 * indirect portmapper call. For this
				 * particular case, we don't increment the
				 * error counter because we want to keep
				 * sifting for successful replies...
				 */
				if (to->sin_addr.s_addr !=
				    ntohl(INADDR_BROADCAST))
					errors++;
				break;

			case RPC_PROGVERSMISMATCH:
				/*
				 * Successfully talked to server, but they
				 * don't speak our lingo.
				 */
				goto gt_error;

			default:
				/* Just keep trying till there's no data... */
				errors++;
				break;
			}

			if (rpc_error.re_status != RPC_SUCCESS) {
				dprintf("brpc_call: from: %s, error: ",
				    inet_ntoa(from_who->sin_addr));
				rpc_disperr(&rpc_error);
			} else
				break;
		}

		/*
		 * If we're having trouble reassembling datagrams, let the
		 * application know ASAP so that it can take the appropriate
		 * actions.
		 */

	} while (rpc_error.re_status != RPC_SUCCESS && errno != ETIMEDOUT &&
	    prom_gettime() < wait_time);

gt_error:
	if (xmit_auth != NULL)
		AUTH_DESTROY(xmit_auth);

	if (trm_msg != NULL)
		bkmem_free(trm_msg, trm_len);
	if (rcv_msg != NULL)
		bkmem_free(rcv_msg, NFSBUF_SIZE);

	if (rpc_error.re_status != RPC_SUCCESS)
		rpc_disperr(&rpc_error);

	/*
	 * socket calls reset errno. Since we want to hold onto the errno
	 * value if it is ETIMEDOUT to communicate to our caller that this
	 * RPC_TIMEDOUT situation is due to a stack problem (we're getting
	 * a reply, but the stack simply can't assemble it.), we need to
	 * preserve errno's value over the socket_close().
	 */
	preserve_errno = (errno == ETIMEDOUT) ? errno : 0;
	(void) socket_close(s);
	errno = preserve_errno;

	return (rpc_error.re_status);
}
/* ARGSUSED */
static enum clnt_stat
clnt_rdma_kcallit(CLIENT *h, rpcproc_t procnum, xdrproc_t xdr_args,
    caddr_t argsp, xdrproc_t xdr_results, caddr_t resultsp,
    struct timeval wait)
{
	cku_private_t *p = htop(h);

	int 	try_call_again;
	int	refresh_attempt = AUTH_REFRESH_COUNT;
	int 	status;
	int 	msglen;

	XDR	*call_xdrp, callxdr; /* for xdrrdma encoding the RPC call */
	XDR	*reply_xdrp, replyxdr; /* for xdrrdma decoding the RPC reply */
	XDR 	*rdmahdr_o_xdrs, *rdmahdr_i_xdrs;

	struct rpc_msg 	reply_msg;
	rdma_registry_t	*m;

	struct clist *cl_sendlist;
	struct clist *cl_recvlist;
	struct clist *cl;
	struct clist *cl_rpcmsg;
	struct clist *cl_rdma_reply;
	struct clist *cl_rpcreply_wlist;
	struct clist *cl_long_reply;
	rdma_buf_t  rndup;

	uint_t vers;
	uint_t op;
	uint_t off;
	uint32_t seg_array_len;
	uint_t long_reply_len;
	uint_t rpcsec_gss;
	uint_t gss_i_or_p;

	CONN *conn = NULL;
	rdma_buf_t clmsg;
	rdma_buf_t rpcmsg;
	rdma_chunkinfo_lengths_t rcil;

	clock_t	ticks;
	bool_t wlist_exists_reply;

	uint32_t rdma_credit = rdma_bufs_rqst;

	RCSTAT_INCR(rccalls);

call_again:

	bzero(&clmsg, sizeof (clmsg));
	bzero(&rpcmsg, sizeof (rpcmsg));
	bzero(&rndup, sizeof (rndup));
	try_call_again = 0;
	cl_sendlist = NULL;
	cl_recvlist = NULL;
	cl = NULL;
	cl_rpcmsg = NULL;
	cl_rdma_reply = NULL;
	call_xdrp = NULL;
	reply_xdrp = NULL;
	wlist_exists_reply  = FALSE;
	cl_rpcreply_wlist = NULL;
	cl_long_reply = NULL;
	rcil.rcil_len = 0;
	rcil.rcil_len_alt = 0;
	long_reply_len = 0;

	rw_enter(&rdma_lock, RW_READER);
	m = (rdma_registry_t *)p->cku_rd_handle;
	if (m->r_mod_state == RDMA_MOD_INACTIVE) {
		/*
		 * If we didn't find a matching RDMA module in the registry
		 * then there is no transport.
		 */
		rw_exit(&rdma_lock);
		p->cku_err.re_status = RPC_CANTSEND;
		p->cku_err.re_errno = EIO;
		ticks = clnt_rdma_min_delay * drv_usectohz(1000000);
		if (h->cl_nosignal == TRUE) {
			delay(ticks);
		} else {
			if (delay_sig(ticks) == EINTR) {
				p->cku_err.re_status = RPC_INTR;
				p->cku_err.re_errno = EINTR;
			}
		}
		return (RPC_CANTSEND);
	}
	/*
	 * Get unique xid
	 */
	if (p->cku_xid == 0)
		p->cku_xid = alloc_xid();

	status = RDMA_GET_CONN(p->cku_rd_mod->rdma_ops, &p->cku_srcaddr,
	    &p->cku_addr, p->cku_addrfmly, p->cku_rd_handle, &conn);
	rw_exit(&rdma_lock);

	/*
	 * If there is a problem with the connection reflect the issue
	 * back to the higher level to address, we MAY delay for a short
	 * period so that we are kind to the transport.
	 */
	if (conn == NULL) {
		/*
		 * Connect failed to server. Could be because of one
		 * of several things. In some cases we don't want
		 * the caller to retry immediately - delay before
		 * returning to caller.
		 */
		switch (status) {
		case RDMA_TIMEDOUT:
			/*
			 * Already timed out. No need to delay
			 * some more.
			 */
			p->cku_err.re_status = RPC_TIMEDOUT;
			p->cku_err.re_errno = ETIMEDOUT;
			break;
		case RDMA_INTR:
			/*
			 * Failed because of an signal. Very likely
			 * the caller will not retry.
			 */
			p->cku_err.re_status = RPC_INTR;
			p->cku_err.re_errno = EINTR;
			break;
		default:
			/*
			 * All other failures - server down or service
			 * down or temporary resource failure. Delay before
			 * returning to caller.
			 */
			ticks = clnt_rdma_min_delay * drv_usectohz(1000000);
			p->cku_err.re_status = RPC_CANTCONNECT;
			p->cku_err.re_errno = EIO;

			if (h->cl_nosignal == TRUE) {
				delay(ticks);
			} else {
				if (delay_sig(ticks) == EINTR) {
					p->cku_err.re_status = RPC_INTR;
					p->cku_err.re_errno = EINTR;
				}
			}
			break;
		}

		return (p->cku_err.re_status);
	}

	if (p->cku_srcaddr.maxlen < conn->c_laddr.len) {
		if ((p->cku_srcaddr.maxlen != 0) &&
		    (p->cku_srcaddr.buf != NULL))
			kmem_free(p->cku_srcaddr.buf, p->cku_srcaddr.maxlen);
		p->cku_srcaddr.buf = kmem_zalloc(conn->c_laddr.maxlen,
		    KM_SLEEP);
		p->cku_srcaddr.maxlen = conn->c_laddr.maxlen;
	}

	p->cku_srcaddr.len = conn->c_laddr.len;
	bcopy(conn->c_laddr.buf, p->cku_srcaddr.buf, conn->c_laddr.len);

	clnt_check_credit(conn);

	status = CLNT_RDMA_FAIL;

	rpcsec_gss = gss_i_or_p = FALSE;

	if (IS_RPCSEC_GSS(h)) {
		rpcsec_gss = TRUE;
		if (rpc_gss_get_service_type(h->cl_auth) ==
		    rpc_gss_svc_integrity ||
		    rpc_gss_get_service_type(h->cl_auth) ==
		    rpc_gss_svc_privacy)
			gss_i_or_p = TRUE;
	}

	/*
	 * Try a regular RDMA message if RPCSEC_GSS is not being used
	 * or if RPCSEC_GSS is being used for authentication only.
	 */
	if (rpcsec_gss == FALSE ||
	    (rpcsec_gss == TRUE && gss_i_or_p == FALSE)) {
		/*
		 * Grab a send buffer for the request.  Try to
		 * encode it to see if it fits. If not, then it
		 * needs to be sent in a chunk.
		 */
		rpcmsg.type = SEND_BUFFER;
		if (rdma_buf_alloc(conn, &rpcmsg)) {
			DTRACE_PROBE(krpc__e__clntrdma__callit_nobufs);
			goto done;
		}

		/* First try to encode into regular send buffer */
		op = RDMA_MSG;

		call_xdrp = &callxdr;

		xdrrdma_create(call_xdrp, rpcmsg.addr, rpcmsg.len,
		    rdma_minchunk, NULL, XDR_ENCODE, conn);

		status = clnt_compose_rpcmsg(h, procnum, &rpcmsg, call_xdrp,
		    xdr_args, argsp);

		if (status != CLNT_RDMA_SUCCESS) {
			/* Clean up from previous encode attempt */
			rdma_buf_free(conn, &rpcmsg);
			XDR_DESTROY(call_xdrp);
		} else {
			XDR_CONTROL(call_xdrp, XDR_RDMA_GET_CHUNK_LEN, &rcil);
		}
	}

	/* If the encode didn't work, then try a NOMSG */
	if (status != CLNT_RDMA_SUCCESS) {

		msglen = CKU_HDRSIZE + BYTES_PER_XDR_UNIT + MAX_AUTH_BYTES +
		    xdr_sizeof(xdr_args, argsp);

		msglen = calc_length(msglen);

		/* pick up the lengths for the reply buffer needed */
		(void) xdrrdma_sizeof(xdr_args, argsp, 0,
		    &rcil.rcil_len, &rcil.rcil_len_alt);

		/*
		 * Construct a clist to describe the CHUNK_BUFFER
		 * for the rpcmsg.
		 */
		cl_rpcmsg = clist_alloc();
		cl_rpcmsg->c_len = msglen;
		cl_rpcmsg->rb_longbuf.type = RDMA_LONG_BUFFER;
		cl_rpcmsg->rb_longbuf.len = msglen;
		if (rdma_buf_alloc(conn, &cl_rpcmsg->rb_longbuf)) {
			clist_free(cl_rpcmsg);
			goto done;
		}
		cl_rpcmsg->w.c_saddr3 = cl_rpcmsg->rb_longbuf.addr;

		op = RDMA_NOMSG;
		call_xdrp = &callxdr;

		xdrrdma_create(call_xdrp, cl_rpcmsg->rb_longbuf.addr,
		    cl_rpcmsg->rb_longbuf.len, 0,
		    cl_rpcmsg, XDR_ENCODE, conn);

		status = clnt_compose_rpcmsg(h, procnum, &rpcmsg, call_xdrp,
		    xdr_args, argsp);

		if (status != CLNT_RDMA_SUCCESS) {
			p->cku_err.re_status = RPC_CANTENCODEARGS;
			p->cku_err.re_errno = EIO;
			DTRACE_PROBE(krpc__e__clntrdma__callit__composemsg);
			goto done;
		}
	}

	/*
	 * During the XDR_ENCODE we may have "allocated" an RDMA READ or
	 * RDMA WRITE clist.
	 *
	 * First pull the RDMA READ chunk list from the XDR private
	 * area to keep it handy.
	 */
	XDR_CONTROL(call_xdrp, XDR_RDMA_GET_RLIST, &cl);

	if (gss_i_or_p) {
		long_reply_len = rcil.rcil_len + rcil.rcil_len_alt;
		long_reply_len += MAX_AUTH_BYTES;
	} else {
		long_reply_len = rcil.rcil_len;
	}

	/*
	 * Update the chunk size information for the Long RPC msg.
	 */
	if (cl && op == RDMA_NOMSG)
		cl->c_len = p->cku_outsz;

	/*
	 * Prepare the RDMA header. On success xdrs will hold the result
	 * of xdrmem_create() for a SEND_BUFFER.
	 */
	status = clnt_compose_rdma_header(conn, h, &clmsg,
	    &rdmahdr_o_xdrs, &op);

	if (status != CLNT_RDMA_SUCCESS) {
		p->cku_err.re_status = RPC_CANTSEND;
		p->cku_err.re_errno = EIO;
		RCSTAT_INCR(rcnomem);
		DTRACE_PROBE(krpc__e__clntrdma__callit__nobufs2);
		goto done;
	}

	/*
	 * Now insert the RDMA READ list iff present
	 */
	status = clnt_setup_rlist(conn, rdmahdr_o_xdrs, call_xdrp);
	if (status != CLNT_RDMA_SUCCESS) {
		DTRACE_PROBE(krpc__e__clntrdma__callit__clistreg);
		rdma_buf_free(conn, &clmsg);
		p->cku_err.re_status = RPC_CANTSEND;
		p->cku_err.re_errno = EIO;
		goto done;
	}

	/*
	 * Setup RDMA WRITE chunk list for nfs read operation
	 * other operations will have a NULL which will result
	 * as a NULL list in the XDR stream.
	 */
	status = clnt_setup_wlist(conn, rdmahdr_o_xdrs, call_xdrp, &rndup);
	if (status != CLNT_RDMA_SUCCESS) {
		rdma_buf_free(conn, &clmsg);
		p->cku_err.re_status = RPC_CANTSEND;
		p->cku_err.re_errno = EIO;
		goto done;
	}

	/*
	 * If NULL call and RPCSEC_GSS, provide a chunk such that
	 * large responses can flow back to the client.
	 * If RPCSEC_GSS with integrity or privacy is in use, get chunk.
	 */
	if ((procnum == 0 && rpcsec_gss == TRUE) ||
	    (rpcsec_gss == TRUE && gss_i_or_p == TRUE))
		long_reply_len += 1024;

	status = clnt_setup_long_reply(conn, &cl_long_reply, long_reply_len);

	if (status != CLNT_RDMA_SUCCESS) {
		rdma_buf_free(conn, &clmsg);
		p->cku_err.re_status = RPC_CANTSEND;
		p->cku_err.re_errno = EIO;
		goto done;
	}

	/*
	 * XDR encode the RDMA_REPLY write chunk
	 */
	seg_array_len = (cl_long_reply ? 1 : 0);
	(void) xdr_encode_reply_wchunk(rdmahdr_o_xdrs, cl_long_reply,
	    seg_array_len);

	/*
	 * Construct a clist in "sendlist" that represents what we
	 * will push over the wire.
	 *
	 * Start with the RDMA header and clist (if any)
	 */
	clist_add(&cl_sendlist, 0, XDR_GETPOS(rdmahdr_o_xdrs), &clmsg.handle,
	    clmsg.addr, NULL, NULL);

	/*
	 * Put the RPC call message in  sendlist if small RPC
	 */
	if (op == RDMA_MSG) {
		clist_add(&cl_sendlist, 0, p->cku_outsz, &rpcmsg.handle,
		    rpcmsg.addr, NULL, NULL);
	} else {
		/* Long RPC already in chunk list */
		RCSTAT_INCR(rclongrpcs);
	}

	/*
	 * Set up a reply buffer ready for the reply
	 */
	status = rdma_clnt_postrecv(conn, p->cku_xid);
	if (status != RDMA_SUCCESS) {
		rdma_buf_free(conn, &clmsg);
		p->cku_err.re_status = RPC_CANTSEND;
		p->cku_err.re_errno = EIO;
		goto done;
	}

	/*
	 * sync the memory for dma
	 */
	if (cl != NULL) {
		status = clist_syncmem(conn, cl, CLIST_REG_SOURCE);
		if (status != RDMA_SUCCESS) {
			(void) rdma_clnt_postrecv_remove(conn, p->cku_xid);
			rdma_buf_free(conn, &clmsg);
			p->cku_err.re_status = RPC_CANTSEND;
			p->cku_err.re_errno = EIO;
			goto done;
		}
	}

	/*
	 * Send the RDMA Header and RPC call message to the server
	 */
	status = RDMA_SEND(conn, cl_sendlist, p->cku_xid);
	if (status != RDMA_SUCCESS) {
		(void) rdma_clnt_postrecv_remove(conn, p->cku_xid);
		p->cku_err.re_status = RPC_CANTSEND;
		p->cku_err.re_errno = EIO;
		goto done;
	}

	/*
	 * RDMA plugin now owns the send msg buffers.
	 * Clear them out and don't free them.
	 */
	clmsg.addr = NULL;
	if (rpcmsg.type == SEND_BUFFER)
		rpcmsg.addr = NULL;

	/*
	 * Recv rpc reply
	 */
	status = RDMA_RECV(conn, &cl_recvlist, p->cku_xid);

	/*
	 * Now check recv status
	 */
	if (status != 0) {
		if (status == RDMA_INTR) {
			p->cku_err.re_status = RPC_INTR;
			p->cku_err.re_errno = EINTR;
			RCSTAT_INCR(rcintrs);
		} else if (status == RPC_TIMEDOUT) {
			p->cku_err.re_status = RPC_TIMEDOUT;
			p->cku_err.re_errno = ETIMEDOUT;
			RCSTAT_INCR(rctimeouts);
		} else {
			p->cku_err.re_status = RPC_CANTRECV;
			p->cku_err.re_errno = EIO;
		}
		goto done;
	}

	/*
	 * Process the reply message.
	 *
	 * First the chunk list (if any)
	 */
	rdmahdr_i_xdrs = &(p->cku_inxdr);
	xdrmem_create(rdmahdr_i_xdrs,
	    (caddr_t)(uintptr_t)cl_recvlist->w.c_saddr3,
	    cl_recvlist->c_len, XDR_DECODE);

	/*
	 * Treat xid as opaque (xid is the first entity
	 * in the rpc rdma message).
	 * Skip xid and set the xdr position accordingly.
	 */
	XDR_SETPOS(rdmahdr_i_xdrs, sizeof (uint32_t));
	(void) xdr_u_int(rdmahdr_i_xdrs, &vers);
	(void) xdr_u_int(rdmahdr_i_xdrs, &rdma_credit);
	(void) xdr_u_int(rdmahdr_i_xdrs, &op);
	(void) xdr_do_clist(rdmahdr_i_xdrs, &cl);

	clnt_update_credit(conn, rdma_credit);

	wlist_exists_reply = FALSE;
	if (! xdr_decode_wlist(rdmahdr_i_xdrs, &cl_rpcreply_wlist,
	    &wlist_exists_reply)) {
		DTRACE_PROBE(krpc__e__clntrdma__callit__wlist_decode);
		p->cku_err.re_status = RPC_CANTDECODERES;
		p->cku_err.re_errno = EIO;
		goto done;
	}

	/*
	 * The server shouldn't have sent a RDMA_SEND that
	 * the client needs to RDMA_WRITE a reply back to
	 * the server.  So silently ignoring what the
	 * server returns in the rdma_reply section of the
	 * header.
	 */
	(void) xdr_decode_reply_wchunk(rdmahdr_i_xdrs, &cl_rdma_reply);
	off = xdr_getpos(rdmahdr_i_xdrs);

	clnt_decode_long_reply(conn, cl_long_reply,
	    cl_rdma_reply, &replyxdr, &reply_xdrp,
	    cl, cl_recvlist, op, off);

	if (reply_xdrp == NULL)
		goto done;

	if (wlist_exists_reply) {
		XDR_CONTROL(reply_xdrp, XDR_RDMA_SET_WLIST, cl_rpcreply_wlist);
	}

	reply_msg.rm_direction = REPLY;
	reply_msg.rm_reply.rp_stat = MSG_ACCEPTED;
	reply_msg.acpted_rply.ar_stat = SUCCESS;
	reply_msg.acpted_rply.ar_verf = _null_auth;

	/*
	 *  xdr_results will be done in AUTH_UNWRAP.
	 */
	reply_msg.acpted_rply.ar_results.where = NULL;
	reply_msg.acpted_rply.ar_results.proc = xdr_void;

	/*
	 * Decode and validate the response.
	 */
	if (xdr_replymsg(reply_xdrp, &reply_msg)) {
		enum clnt_stat re_status;

		_seterr_reply(&reply_msg, &(p->cku_err));

		re_status = p->cku_err.re_status;
		if (re_status == RPC_SUCCESS) {
			/*
			 * Reply is good, check auth.
			 */
			if (!AUTH_VALIDATE(h->cl_auth,
			    &reply_msg.acpted_rply.ar_verf)) {
				p->cku_err.re_status = RPC_AUTHERROR;
				p->cku_err.re_why = AUTH_INVALIDRESP;
				RCSTAT_INCR(rcbadverfs);
				DTRACE_PROBE(
				    krpc__e__clntrdma__callit__authvalidate);
			} else if (!AUTH_UNWRAP(h->cl_auth, reply_xdrp,
			    xdr_results, resultsp)) {
				p->cku_err.re_status = RPC_CANTDECODERES;
				p->cku_err.re_errno = EIO;
				DTRACE_PROBE(
				    krpc__e__clntrdma__callit__authunwrap);
			}
		} else {
			/* set errno in case we can't recover */
			if (re_status != RPC_VERSMISMATCH &&
			    re_status != RPC_AUTHERROR &&
			    re_status != RPC_PROGVERSMISMATCH)
				p->cku_err.re_errno = EIO;

			if (re_status == RPC_AUTHERROR) {
				if ((refresh_attempt > 0) &&
				    AUTH_REFRESH(h->cl_auth, &reply_msg,
				    p->cku_cred)) {
					refresh_attempt--;
					try_call_again = 1;
					goto done;
				}

				try_call_again = 0;

				/*
				 * We have used the client handle to
				 * do an AUTH_REFRESH and the RPC status may
				 * be set to RPC_SUCCESS; Let's make sure to
				 * set it to RPC_AUTHERROR.
				 */
				p->cku_err.re_status = RPC_AUTHERROR;

				/*
				 * Map recoverable and unrecoverable
				 * authentication errors to appropriate
				 * errno
				 */
				switch (p->cku_err.re_why) {
				case AUTH_BADCRED:
				case AUTH_BADVERF:
				case AUTH_INVALIDRESP:
				case AUTH_TOOWEAK:
				case AUTH_FAILED:
				case RPCSEC_GSS_NOCRED:
				case RPCSEC_GSS_FAILED:
					p->cku_err.re_errno = EACCES;
					break;
				case AUTH_REJECTEDCRED:
				case AUTH_REJECTEDVERF:
				default:
					p->cku_err.re_errno = EIO;
					break;
				}
			}
			DTRACE_PROBE1(krpc__e__clntrdma__callit__rpcfailed,
			    int, p->cku_err.re_why);
		}
	} else {
Exemple #15
0
static enum clnt_stat
clntraw_call (CLIENT *h, u_long proc, xdrproc_t xargs, caddr_t argsp,
	      xdrproc_t xresults, caddr_t resultsp, struct timeval timeout)
{
  struct clntraw_private_s *clp = clntraw_private;
  XDR *xdrs = &clp->xdr_stream;
  struct rpc_msg msg;
  enum clnt_stat status;
  struct rpc_err error;

  if (clp == NULL)
    return RPC_FAILED;
call_again:
  /*
   * send request
   */
  xdrs->x_op = XDR_ENCODE;
  XDR_SETPOS (xdrs, 0);
  /* Just checking the union definition to access rm_xid is correct.  */
  if (offsetof (struct rpc_msg, rm_xid) != 0)
    abort ();
  clp->mashl_callmsg.rm_xid++;
  if ((!XDR_PUTBYTES (xdrs, clp->mashl_callmsg.msg, clp->mcnt)) ||
      (!XDR_PUTLONG (xdrs, (long *) &proc)) ||
      (!AUTH_MARSHALL (h->cl_auth, xdrs)) ||
      (!(*xargs) (xdrs, argsp)))
    {
      return (RPC_CANTENCODEARGS);
    }
  (void) XDR_GETPOS (xdrs);	/* called just to cause overhead */

  /*
   * We have to call server input routine here because this is
   * all going on in one process. Yuk.
   */
  svc_getreq (1);

  /*
   * get results
   */
  xdrs->x_op = XDR_DECODE;
  XDR_SETPOS (xdrs, 0);
  msg.acpted_rply.ar_verf = _null_auth;
  msg.acpted_rply.ar_results.where = resultsp;
  msg.acpted_rply.ar_results.proc = xresults;
  if (!xdr_replymsg (xdrs, &msg))
    return RPC_CANTDECODERES;
  _seterr_reply (&msg, &error);
  status = error.re_status;

  if (status == RPC_SUCCESS)
    {
      if (!AUTH_VALIDATE (h->cl_auth, &msg.acpted_rply.ar_verf))
	{
	  status = RPC_AUTHERROR;
	}
    }				/* end successful completion */
  else
    {
      if (AUTH_REFRESH (h->cl_auth))
	goto call_again;
    }				/* end of unsuccessful completion */

  if (status == RPC_SUCCESS)
    {
      if (!AUTH_VALIDATE (h->cl_auth, &msg.acpted_rply.ar_verf))
	{
	  status = RPC_AUTHERROR;
	}
      if (msg.acpted_rply.ar_verf.oa_base != NULL)
	{
	  xdrs->x_op = XDR_FREE;
	  (void) xdr_opaque_auth (xdrs, &(msg.acpted_rply.ar_verf));
	}
    }

  return status;
}