Example #1
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);
}
static int
clnt_compose_rpcmsg(CLIENT *h, rpcproc_t procnum,
    rdma_buf_t *rpcmsg, XDR *xdrs,
    xdrproc_t xdr_args, caddr_t argsp)
{
	cku_private_t *p = htop(h);

	if (h->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) {
		/*
		 * Copy in the preserialized RPC header
		 * information.
		 */
		bcopy(p->cku_rpchdr, rpcmsg->addr, CKU_HDRSIZE);

		/*
		 * transaction id is the 1st thing in the output
		 * buffer.
		 */
		/* LINTED pointer alignment */
		(*(uint32_t *)(rpcmsg->addr)) = p->cku_xid;

		/* Skip the preserialized stuff. */
		XDR_SETPOS(xdrs, CKU_HDRSIZE);

		/* Serialize dynamic stuff into the output buffer. */
		if ((!XDR_PUTINT32(xdrs, (int32_t *)&procnum)) ||
		    (!AUTH_MARSHALL(h->cl_auth, xdrs, p->cku_cred)) ||
		    (!(*xdr_args)(xdrs, argsp))) {
			DTRACE_PROBE(krpc__e__clntrdma__rpcmsg__dynargs);
			return (CLNT_RDMA_FAIL);
		}
		p->cku_outsz = XDR_GETPOS(xdrs);
	} else {
		uint32_t *uproc = (uint32_t *)&p->cku_rpchdr[CKU_HDRSIZE];
		IXDR_PUT_U_INT32(uproc, procnum);
		(*(uint32_t *)(&p->cku_rpchdr[0])) = p->cku_xid;
		XDR_SETPOS(xdrs, 0);

		/* Serialize the procedure number and the arguments. */
		if (!AUTH_WRAP(h->cl_auth, (caddr_t)p->cku_rpchdr,
		    CKU_HDRSIZE+4, xdrs, xdr_args, argsp)) {
			if (rpcmsg->addr != xdrs->x_base) {
				rpcmsg->addr = xdrs->x_base;
				rpcmsg->len = xdr_getbufsize(xdrs);
			}
			DTRACE_PROBE(krpc__e__clntrdma__rpcmsg__procnum);
			return (CLNT_RDMA_FAIL);
		}
		/*
		 * If we had to allocate a new buffer while encoding
		 * then update the addr and len.
		 */
		if (rpcmsg->addr != xdrs->x_base) {
			rpcmsg->addr = xdrs->x_base;
			rpcmsg->len = xdr_getbufsize(xdrs);
		}

		p->cku_outsz = XDR_GETPOS(xdrs);
		DTRACE_PROBE1(krpc__i__compose__size__sec, int, p->cku_outsz)
	}

	return (CLNT_RDMA_SUCCESS);
}
Example #3
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);
}
Example #4
0
File: clnt_tcp.c Project: PADL/krb5
static enum clnt_stat
clnttcp_call(
	CLIENT *h,
	rpcproc_t proc,
	xdrproc_t xdr_args,
	void * args_ptr,
	xdrproc_t xdr_results,
	void * results_ptr,
	struct timeval timeout)
{
	struct ct_data *ct = h->cl_private;
	XDR *xdrs = &ct->ct_xdrs;
	struct rpc_msg reply_msg;
	uint32_t x_id;
	uint32_t *msg_x_id = &ct->ct_u.ct_mcalli;	/* yuk */
	bool_t shipnow;
	int refreshes = 2;
	long procl = proc;

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

	shipnow =
	    (xdr_results == (xdrproc_t)0 && 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_mcall, ct->ct_mpos)) ||
	    (! XDR_PUTLONG(xdrs, &procl)) ||
	    (! AUTH_MARSHALL(h->cl_auth, xdrs)) ||
	    (! AUTH_WRAP(h->cl_auth, 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);
		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 = gssrpc__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)) {
			/*
			 * Free some stuff allocated by xdr_replymsg()
			 * to avoid leaks, since it may allocate
			 * memory from partially successful decodes.
			 */
			enum xdr_op op = xdrs->x_op;
			xdrs->x_op = XDR_FREE;
			xdr_replymsg(xdrs, &reply_msg);
			xdrs->x_op = op;
			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
	 */
	gssrpc__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 (! AUTH_UNWRAP(h->cl_auth, xdrs,
					 xdr_results, results_ptr)) {
			if (ct->ct_error.re_status == RPC_SUCCESS)
				ct->ct_error.re_status = RPC_CANTDECODERES;
		}
	}  /* end successful completion */
	else {
		/* maybe our credentials need to be refreshed ... */
		if (refreshes-- && AUTH_REFRESH(h->cl_auth, &reply_msg))
			goto call_again;
	}  /* end of unsuccessful completion */
	/* free verifier ... */
	if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
	    (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));
	}
	return (ct->ct_error.re_status);
}