Пример #1
0
int
rtime(struct knetconfig *synconfig, struct netbuf *addrp, int calltype,
	struct timeval *timep, struct timeval *wait)
{
	int			error;
	int			timo;
	time_t			thetime;
	int32_t			srvtime;
	uint32_t		dummy;
	struct t_kunitdata	*unitdata;
	struct t_call		*server;
	TIUSER			*tiptr;
	int			type;
	int			uderr;
	int			i;
	int			retries;
	mblk_t			*mp;
	mblk_t			*mp2;

	retries = 5;
	if (calltype == 0) {
again:
		RPCLOG0(8, "rtime: using old method\n");
		if ((error = t_kopen(NULL, synconfig->knc_rdev,
		    FREAD|FWRITE, &tiptr, CRED())) != 0) {
			RPCLOG(1, "rtime: t_kopen %d\n", error);
			return (-1);
		}

		if ((error = t_kbind(tiptr, NULL, NULL)) != 0) {
			(void) t_kclose(tiptr, 1);
			RPCLOG(1, "rtime: t_kbind %d\n", error);
			return (-1);
		}

		if (synconfig->knc_semantics == NC_TPI_CLTS) {
			if ((error = t_kalloc(tiptr, T_UNITDATA,
			    T_UDATA|T_ADDR, (char **)&unitdata)) != 0) {
				RPCLOG(1, "rtime: t_kalloc %d\n", error);
				(void) t_kclose(tiptr, 1);
				return (-1);
			}

			unitdata->addr.len = addrp->len;
			bcopy(addrp->buf, unitdata->addr.buf,
			    unitdata->addr.len);

			dummy = 0;
			unitdata->udata.buf = (caddr_t)&dummy;
			unitdata->udata.len = sizeof (dummy);

			if ((error = t_ksndudata(tiptr, unitdata, NULL)) !=
			    0) {
				RPCLOG(1, "rtime: t_ksndudata %d\n", error);
				(void) t_kfree(tiptr, (char *)unitdata,
				    T_UNITDATA);
				(void) t_kclose(tiptr, 1);
				return (-1);
			}

			timo = TIMEVAL_TO_TICK(wait);

			RPCLOG(8, "rtime: timo %x\n", timo);
			if ((error = t_kspoll(tiptr, timo, READWAIT,
			    &type)) != 0) {
				RPCLOG(1, "rtime: t_kspoll %d\n", error);
				(void) t_kfree(tiptr, (char *)unitdata,
				    T_UNITDATA);
				(void) t_kclose(tiptr, 1);
				return (-1);
			}

			if (type == 0) {
				RPCLOG0(1, "rtime: t_kspoll timed out\n");
				(void) t_kfree(tiptr, (char *)unitdata,
				    T_UNITDATA);
				(void) t_kclose(tiptr, 1);
				return (-1);
			}

			error = t_krcvudata(tiptr, unitdata, &type, &uderr);
			if (error != 0) {
				RPCLOG(1, "rtime: t_krcvudata %d\n", error);
				(void) t_kfree(tiptr, (char *)unitdata,
				    T_UNITDATA);
				(void) t_kclose(tiptr, 1);
				if (error == EBADMSG && retries-- > 0)
					goto again;
				return (-1);
			}

			if (type == T_UDERR) {
				if (bcmp(addrp->buf, unitdata->addr.buf,
				    unitdata->addr.len) != 0) {
				/*
				 * Response comes from some other
				 * destination:
				 * ignore it since it's not related to the
				 * request we just sent out.
				 */
					(void) t_kfree(tiptr, (char *)unitdata,
					    T_UNITDATA);
					(void) t_kclose(tiptr, 1);
					goto again;
				}
			}

			if (type != T_DATA) {
				RPCLOG(1,
				    "rtime: t_krcvudata returned type %d\n",
				    type);
				(void) t_kfree(tiptr, (char *)unitdata,
				    T_UNITDATA);
				(void) t_kclose(tiptr, 1);
				if (retries-- == 0)
					return (-1);
				goto again;
			}

			if (unitdata->udata.len < sizeof (uint32_t)) {
				RPCLOG(1, "rtime: bad rcvd length %d\n",
				    unitdata->udata.len);
				(void) t_kfree(tiptr, (char *)unitdata,
				    T_UNITDATA);
				(void) t_kclose(tiptr, 1);
				if (retries-- == 0)
					return (-1);
				goto again;
			}

			thetime = (time_t)ntohl(
			    /* LINTED pointer alignment */
			    *(uint32_t *)unitdata->udata.buf);
			(void) t_kfree(tiptr, (char *)unitdata, T_UNITDATA);

		} else {

			if ((error = t_kalloc(tiptr, T_CALL, T_ADDR,
			    (char **)&server)) != 0) {
				RPCLOG(1, "rtime: t_kalloc %d\n", error);
				(void) t_kclose(tiptr, 1);
				return (-1);
			}

			server->addr.len = addrp->len;
			bcopy(addrp->buf, server->addr.buf, server->addr.len);

			if ((error = t_kconnect(tiptr, server, NULL)) != 0) {
				RPCLOG(1, "rtime: t_kconnect %d\n", error);
				(void) t_kfree(tiptr, (char *)server, T_CALL);
				(void) t_kclose(tiptr, 1);
				return (-1);
			}
			(void) t_kfree(tiptr, (char *)server, T_CALL);

			timo = TIMEVAL_TO_TICK(wait);

			RPCLOG(8, "rtime: timo %x\n", timo);

			i = 0;
			dummy = 0;

			/* now read up to 4 bytes from the TIME server */
			while (i < sizeof (dummy)) {

				error = t_kspoll(tiptr, timo, READWAIT, &type);
				if (error != 0) {
					RPCLOG(1, "rtime: t_kspoll %d\n",
					    error);
					(void) t_kclose(tiptr, 1);
					return (-1);
				}

				if (type == 0) {
					RPCLOG0(1,
					    "rtime: t_kspoll timed out\n");
					(void) t_kclose(tiptr, 1);
					return (-1);
				}

				error = tli_recv(tiptr, &mp,
				    tiptr->fp->f_flag);
				if (error != 0) {
					RPCLOG(1, "rtime: tli_recv %d\n",
					    error);
					(void) t_kclose(tiptr, 1);
					return (-1);
				}

				if (mp->b_datap->db_type != M_DATA) {
					RPCLOG(1, "rtime: wrong msg type %d\n",
					    mp->b_datap->db_type);
					RPCLOG(1,
					    "rtime: wrong msg type: read %d"
					    " bytes\n", i);
					(void) t_kclose(tiptr, 1);
					freemsg(mp);
					return (-1);
				}

				mp2 = mp;

				/*
				 * The outer loop iterates until we reach the
				 * end of the mblk chain.
				 */
				while (mp2 != NULL) {

					/*
					 * The inner loop iterates until
					 * we've gotten 4 bytes or until
					 * the mblk is exhausted.
					 */
					while (i < sizeof (dummy) &&
					    mp2->b_rptr < mp2->b_wptr) {

						i++;

					/*
					 * We avoid big-endian/little-endian
					 * issues by serializing the result
					 * one byte at a time.
					 */
						dummy <<= 8;
						dummy += ((*mp2->b_rptr) &
						    0xFF);

						mp2->b_rptr++;
					}

					mp2 = mp2->b_cont;
				}

			freemsg(mp);
			}

			thetime = (time_t)dummy;
		}

		(void) t_kclose(tiptr, 1);

	} else {
		CLIENT			*client;
		struct timeval		timout;

		RPCLOG0(8, "rtime: using new method\n");

new_again:
		/*
		 *	We talk to rpcbind.
		 */
		error = clnt_tli_kcreate(synconfig, addrp, (rpcprog_t)RPCBPROG,
		    (rpcvers_t)RPCBVERS, 0, retries, CRED(), &client);

		if (error != 0) {
			RPCLOG(1,
			    "rtime: clnt_tli_kcreate returned %d\n", error);
			return (-1);
		}
		timout.tv_sec = 60;
		timout.tv_usec = 0;
		error = clnt_call(client, RPCBPROC_GETTIME, (xdrproc_t)xdr_void,
		    NULL, (xdrproc_t)xdr_u_int,
		    (caddr_t)&srvtime, timout);
		thetime = srvtime;
		auth_destroy(client->cl_auth);
		clnt_destroy(client);
		if (error == RPC_UDERROR) {
			if (retries-- > 0)
				goto new_again;
		}
		if (error != RPC_SUCCESS) {
			RPCLOG(1, "rtime: time sync clnt_call returned %d\n",
			    error);
			error = EIO;
			return (-1);
		}
	}

	if (calltype != 0)
		thetime += TOFFSET;

	RPCLOG(8, "rtime: thetime = %lx\n", thetime);

	if (thetime < WRITTEN) {
		RPCLOG(1, "rtime: time returned is too far in past %lx",
		    thetime);
		RPCLOG(1, "rtime: WRITTEN %x", WRITTEN);
		return (-1);
	}
	thetime -= TOFFSET;

	timep->tv_sec = thetime;
	RPCLOG(8, "rtime: timep->tv_sec = %lx\n", timep->tv_sec);
	RPCLOG(8, "rtime: machine time  = %lx\n", gethrestime_sec());
	timep->tv_usec = 0;
	RPCLOG0(8, "rtime: returning success\n");
	return (0);
}
Пример #2
0
/*
 * Send rpc reply.
 * Serialize the reply packet into the output buffer then
 * call t_ksndudata to send it.
 */
static bool_t
svc_clts_ksend(SVCXPRT *clone_xprt, struct rpc_msg *msg)
{
	/* LINTED pointer alignment */
	struct udp_data *ud = (struct udp_data *)clone_xprt->xp_p2buf;
	XDR *xdrs = &clone_xprt->xp_xdrout;
	int stat = FALSE;
	mblk_t *mp;
	int msgsz;
	struct T_unitdata_req *udreq;
	xdrproc_t xdr_results;
	caddr_t xdr_location;
	bool_t has_args;

	TRACE_0(TR_FAC_KRPC, TR_SVC_CLTS_KSEND_START,
	    "svc_clts_ksend_start:");

	ASSERT(ud->ud_resp != NULL);

	/*
	 * If there is a result procedure specified in the reply message,
	 * it will be processed in the xdr_replymsg and SVCAUTH_WRAP.
	 * We need to make sure it won't be processed twice, so we null
	 * it for xdr_replymsg here.
	 */
	has_args = FALSE;
	if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
		msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
		if ((xdr_results = msg->acpted_rply.ar_results.proc) != NULL) {
			has_args = TRUE;
			xdr_location = msg->acpted_rply.ar_results.where;
			msg->acpted_rply.ar_results.proc = xdr_void;
			msg->acpted_rply.ar_results.where = NULL;
		}
	}

	if (ud->ud_resp->b_cont == NULL) {
		/*
		 * Allocate an initial mblk for the response data.
		 */
		while ((mp = allocb(UD_INITSIZE, BPRI_LO)) == NULL) {
			if (strwaitbuf(UD_INITSIZE, BPRI_LO)) {
				TRACE_1(TR_FAC_KRPC, TR_SVC_CLTS_KSEND_END,
				    "svc_clts_ksend_end:(%S)", "strwaitbuf");
				return (FALSE);
			}
		}

		/*
		 * Initialize the XDR decode stream.  Additional mblks
		 * will be allocated if necessary.  They will be UD_MAXSIZE
		 * sized.
		 */
		xdrmblk_init(xdrs, mp, XDR_ENCODE, UD_MAXSIZE);

		/*
		 * Leave some space for protocol headers.
		 */
		(void) XDR_SETPOS(xdrs, 512);
		mp->b_rptr += 512;

		msg->rm_xid = clone_xprt->xp_xid;

		ud->ud_resp->b_cont = mp;

		TRACE_0(TR_FAC_KRPC, TR_XDR_REPLYMSG_START,
		    "xdr_replymsg_start:");
		if (!(xdr_replymsg(xdrs, msg) &&
			(!has_args || SVCAUTH_WRAP(&clone_xprt->xp_auth, xdrs,
				xdr_results, xdr_location)))) {
			TRACE_1(TR_FAC_KRPC, TR_XDR_REPLYMSG_END,
			    "xdr_replymsg_end:(%S)", "bad");
			RPCLOG0(1, "xdr_replymsg/SVCAUTH_WRAP failed\n");
			goto out;
		}
		TRACE_1(TR_FAC_KRPC, TR_XDR_REPLYMSG_END,
		    "xdr_replymsg_end:(%S)", "good");

	} else if (!(xdr_replymsg_body(xdrs, msg) &&
		    (!has_args || SVCAUTH_WRAP(&clone_xprt->xp_auth, xdrs,
				xdr_results, xdr_location)))) {
		RPCLOG0(1, "xdr_replymsg_body/SVCAUTH_WRAP failed\n");
		goto out;
	}

	msgsz = (int)xmsgsize(ud->ud_resp->b_cont);

	if (msgsz <= 0 || (clone_xprt->xp_msg_size != -1 &&
	    msgsz > clone_xprt->xp_msg_size)) {
#ifdef	DEBUG
		cmn_err(CE_NOTE,
"KRPC: server response message of %d bytes; transport limits are [0, %d]",
			msgsz, clone_xprt->xp_msg_size);
#endif
		goto out;
	}

	/*
	 * Construct the T_unitdata_req.  We take advantage
	 * of the fact that T_unitdata_ind looks just like
	 * T_unitdata_req, except for the primitive type.
	 */
	udreq = (struct T_unitdata_req *)ud->ud_resp->b_rptr;
	udreq->PRIM_type = T_UNITDATA_REQ;

	put(clone_xprt->xp_wq, ud->ud_resp);
	stat = TRUE;
	ud->ud_resp = NULL;

out:
	if (stat == FALSE) {
		freemsg(ud->ud_resp);
		ud->ud_resp = NULL;
	}

	/*
	 * This is completely disgusting.  If public is set it is
	 * a pointer to a structure whose first field is the address
	 * of the function to free that structure and any related
	 * stuff.  (see rrokfree in nfs_xdr.c).
	 */
	if (xdrs->x_public) {
		/* LINTED pointer alignment */
		(**((int (**)())xdrs->x_public))(xdrs->x_public);
	}

	TRACE_1(TR_FAC_KRPC, TR_SVC_CLTS_KSEND_END,
	    "svc_clts_ksend_end:(%S)", "done");
	return (stat);
}