Ejemplo n.º 1
0
static bool_t Svctcp_reply(SVCXPRT * xprt, register struct rpc_msg *msg)
{
  register struct tcp_conn *cd = (struct tcp_conn *)(xprt->xp_p1);
  register XDR *xdrs = &(cd->xdrs);
  xdrproc_t xdr_proc;
  caddr_t xdr_where;

  xdrs->x_op = XDR_ENCODE;
  msg->rm_xid = cd->x_id;

  if(msg->rm_reply.rp_stat == MSG_ACCEPTED && msg->rm_reply.rp_acpt.ar_stat == SUCCESS)
    {
      xdr_proc = msg->acpted_rply.ar_results.proc;
      xdr_where = msg->acpted_rply.ar_results.where;
      msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void;
      msg->acpted_rply.ar_results.where = NULL;

      if(!xdr_replymsg(xdrs, msg) || !SVCAUTH_WRAP(NULL, xdrs, xdr_proc, xdr_where))
        return (FALSE);
    }
  else if(!xdr_replymsg(xdrs, msg))
    {
      return (FALSE);
    }

  (void)xdrrec_endofrecord(xdrs, TRUE);

  return (TRUE);
}
Ejemplo n.º 2
0
static bool_t
svc_vc_backchannel_reply(SVCXPRT *xprt, struct rpc_msg *msg,
    struct sockaddr *addr, struct mbuf *m, uint32_t *seq)
{
	struct ct_data *ct;
	XDR xdrs;
	struct mbuf *mrep;
	bool_t stat = TRUE;
	int error;

	/*
	 * Leave space for record mark.
	 */
	mrep = m_gethdr(M_WAITOK, MT_DATA);
	mrep->m_data += sizeof(uint32_t);

	xdrmbuf_create(&xdrs, mrep, XDR_ENCODE);

	if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
	    msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
		if (!xdr_replymsg(&xdrs, msg))
			stat = FALSE;
		else
			xdrmbuf_append(&xdrs, m);
	} else {
		stat = xdr_replymsg(&xdrs, msg);
	}

	if (stat) {
		m_fixhdr(mrep);

		/*
		 * Prepend a record marker containing the reply length.
		 */
		M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK);
		*mtod(mrep, uint32_t *) =
			htonl(0x80000000 | (mrep->m_pkthdr.len
				- sizeof(uint32_t)));
		sx_xlock(&xprt->xp_lock);
		ct = (struct ct_data *)xprt->xp_p2;
		if (ct != NULL)
			error = sosend(ct->ct_socket, NULL, NULL, mrep, NULL,
			    0, curthread);
		else
			error = EPIPE;
		sx_xunlock(&xprt->xp_lock);
		if (!error) {
			stat = TRUE;
		}
	} else {
		m_freem(mrep);
	}

	XDR_DESTROY(&xdrs);

	return (stat);
}
Ejemplo n.º 3
0
static bool_t
svc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg,
    struct sockaddr *addr, struct mbuf *m, uint32_t *seq)
{
	XDR xdrs;
	struct mbuf *mrep;
	bool_t stat = TRUE;
	int error, len;

	/*
	 * Leave space for record mark.
	 */
	mrep = m_gethdr(M_WAITOK, MT_DATA);
	mrep->m_data += sizeof(uint32_t);

	xdrmbuf_create(&xdrs, mrep, XDR_ENCODE);

	if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
	    msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
		if (!xdr_replymsg(&xdrs, msg))
			stat = FALSE;
		else
			xdrmbuf_append(&xdrs, m);
	} else {
		stat = xdr_replymsg(&xdrs, msg);
	}

	if (stat) {
		m_fixhdr(mrep);

		/*
		 * Prepend a record marker containing the reply length.
		 */
		M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK);
		len = mrep->m_pkthdr.len;
		*mtod(mrep, uint32_t *) =
			htonl(0x80000000 | (len - sizeof(uint32_t)));
		atomic_add_32(&xprt->xp_snd_cnt, len);
		error = sosend(xprt->xp_socket, NULL, NULL, mrep, NULL,
		    0, curthread);
		if (!error) {
			atomic_add_rel_32(&xprt->xp_snt_cnt, len);
			if (seq)
				*seq = xprt->xp_snd_cnt;
			stat = TRUE;
		} else
			atomic_subtract_32(&xprt->xp_snd_cnt, len);
	} else {
		m_freem(mrep);
	}

	XDR_DESTROY(&xdrs);

	return (stat);
}
Ejemplo n.º 4
0
static bool_t
svc_dg_reply(SVCXPRT *xprt, struct rpc_msg *msg)
{
	struct svc_dg_data *su;
	XDR *xdrs;
	bool_t stat = FALSE;
	size_t slen;

	_DIAGASSERT(xprt != NULL);
	_DIAGASSERT(msg != NULL);

	su = su_data(xprt);
	xdrs = &(su->su_xdrs);

	xdrs->x_op = XDR_ENCODE;
	XDR_SETPOS(xdrs, 0);
	msg->rm_xid = su->su_xid;
	if (xdr_replymsg(xdrs, msg)) {
		slen = XDR_GETPOS(xdrs);
		if (sendto(xprt->xp_fd, rpc_buffer(xprt), slen, 0,
		    (struct sockaddr *)xprt->xp_rtaddr.buf,
		    (socklen_t)xprt->xp_rtaddr.len) == (ssize_t) slen) {
			stat = TRUE;
			if (su->su_cache)
				cache_set(xprt, slen);
		}
	}
	return (stat);
}
Ejemplo n.º 5
0
Archivo: asrv.C Proyecto: vonwenm/pbft
void
svccb::reply (const void *reply, sfs::xdrproc_t xdr, bool nocache)
{
    rpc_msg rm;

    rm.rm_xid = xid ();
    rm.rm_direction = REPLY;
    rm.rm_reply.rp_stat = MSG_ACCEPTED;
    rm.acpted_rply.ar_verf = _null_auth;
    rm.acpted_rply.ar_stat = SUCCESS;
    rm.acpted_rply.ar_results.where = (char *) reply;
    rm.acpted_rply.ar_results.proc
        = reinterpret_cast<sun_xdrproc_t> (xdr ? xdr : srv->tbl[proc ()].xdr_res);

    get_rpc_stats ().end_call (this, ts_start);

    xdrsuio x (XDR_ENCODE);
    if (!xdr_replymsg (x.xdrp (), &rm)) {
        warn ("svccb::reply: xdr_replymsg failed\n");
        delete this;
        return;
    }

    trace (4, "reply %s:%s x=%x\n",
           srv->rpcprog->name, srv->tbl[msg.rm_call.cb_proc].name,
           xidswap (msg.rm_xid));
    if (asrvtrace >= 5 && !xdr && srv->tbl[msg.rm_call.cb_proc].print_res)
        srv->tbl[msg.rm_call.cb_proc].print_res (reply, NULL, asrvtrace - 4,
                "REPLY", "");
    srv->sendreply (this, &x, nocache);
}
Ejemplo n.º 6
0
static bool_t
svcudp_reply(
	register SVCXPRT *xprt, 
	struct rpc_msg *msg) 
{
	register struct svcudp_data *su = su_data(xprt);
	register XDR *xdrs = &(su->su_xdrs);
	register int slen;
	register bool_t stat = FALSE;

	xdrs->x_op = XDR_ENCODE;
	XDR_SETPOS(xdrs, 0);
	msg->rm_xid = su->su_xid;
	if (xdr_replymsg(xdrs, msg)) {
		slen = (int)XDR_GETPOS(xdrs);
		if (sendto(xprt->xp_sock, rpc_buffer(xprt), slen, 0,
		    (struct sockaddr *)&(xprt->xp_raddr), xprt->xp_addrlen)
		    == (ssize_t)slen) {
			stat = TRUE;
			if (su->su_cache) {
				cache_set(xprt, (unsigned long) slen);
			}
		}
	}
	return (stat);
}
Ejemplo n.º 7
0
/* Decodes the XDR format in msgbuf into rpc_msg.
 * The remaining payload is returned into payload.
 */
int
xdr_to_rpc_reply(char *msgbuf, size_t len, struct rpc_msg *reply,
                 struct iovec *payload, char *verfbytes)
{
    XDR xdr;
    int ret = -EINVAL;

    GF_VALIDATE_OR_GOTO("rpc", msgbuf, out);
    GF_VALIDATE_OR_GOTO("rpc", reply, out);

    memset(reply, 0, sizeof(struct rpc_msg));

    reply->acpted_rply.ar_verf = _null_auth;
    reply->acpted_rply.ar_results.where = NULL;
    reply->acpted_rply.ar_results.proc = (xdrproc_t)(xdr_void);

    xdrmem_create(&xdr, msgbuf, len, XDR_DECODE);
    if (!xdr_replymsg(&xdr, reply)) {
        gf_log("rpc", GF_LOG_WARNING, "failed to decode reply msg");
        goto out;
    }
    if (payload) {
        payload->iov_base = xdr_decoded_remaining_addr(xdr);
        payload->iov_len = xdr_decoded_remaining_len(xdr);
    }

    ret = 0;
out:
    return ret;
}
Ejemplo n.º 8
0
static bool_t Svcudp_reply(register SVCXPRT * xprt, struct rpc_msg *msg)
{
  register struct Svcudp_data *su = Su_data(xprt);
  register XDR *xdrs = &(su->su_xdrs);
  register int slen;
  xdrproc_t xdr_proc;
  caddr_t xdr_where;

  xdrs->x_op = XDR_ENCODE;
  XDR_SETPOS(xdrs, 0);
  msg->rm_xid = su->su_xid;

  if(msg->rm_reply.rp_stat == MSG_ACCEPTED && msg->rm_reply.rp_acpt.ar_stat == SUCCESS)
    {
      xdr_proc = msg->acpted_rply.ar_results.proc;
      xdr_where = msg->acpted_rply.ar_results.where;
      msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void;
      msg->acpted_rply.ar_results.where = NULL;

      if(!xdr_replymsg(xdrs, msg) ||
         !SVCAUTH_WRAP(xprt->xp_auth, xdrs, xdr_proc, xdr_where))
        return (FALSE);
    }
  else if(!xdr_replymsg(xdrs, msg))
    {
      return (FALSE);
    }
  slen = (int)XDR_GETPOS(xdrs);

#ifdef _FREEBSD
  if(sendto(xprt->xp_fd,
#else
  if(sendto(xprt->xp_sock,
#endif
            rpc_buffer(xprt),
            slen, 0, (struct sockaddr *)&(xprt->xp_raddr), xprt->xp_addrlen) != slen)
    {
      return (FALSE);
    }
  return (TRUE);
}
Ejemplo n.º 9
0
static bool_t
svc_dg_reply(SVCXPRT *xprt, struct rpc_msg *msg,
    struct sockaddr *addr, struct mbuf *m)
{
	XDR xdrs;
	struct mbuf *mrep;
	bool_t stat = TRUE;
	int error;

	MGETHDR(mrep, M_WAIT, MT_DATA);
	mrep->m_len = 0;

	xdrmbuf_create(&xdrs, mrep, XDR_ENCODE);

	if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
	    msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
		if (!xdr_replymsg(&xdrs, msg))
			stat = FALSE;
		else
			xdrmbuf_append(&xdrs, m);
	} else {
		stat = xdr_replymsg(&xdrs, msg);
	}

	if (stat) {
		m_fixhdr(mrep);
		error = sosend(xprt->xp_socket, addr, NULL, mrep, NULL,
		    0, curthread);
		if (!error) {
			stat = TRUE;
		}
	} else {
		m_freem(mrep);
	}

	XDR_DESTROY(&xdrs);
	xprt->xp_p2 = NULL;

	return (stat);
}
Ejemplo n.º 10
0
Archivo: asrv.C Proyecto: vonwenm/pbft
static void
asrv_accepterr (ref<xhinfo> xi, const sockaddr *addr,
                accept_stat stat, const rpc_msg *mp)
{
    rpc_msg m;

    bzero (&m, sizeof (m));
    m.rm_xid = mp->rm_xid;
    m.rm_direction = REPLY;
    m.rm_reply.rp_stat = MSG_ACCEPTED;

    switch (stat) {
    case PROG_UNAVAIL:
    case PROG_MISMATCH:
    {
        m.acpted_rply.ar_stat = PROG_UNAVAIL;
        m.acpted_rply.ar_vers.low = 0xffffffff;
        m.acpted_rply.ar_vers.high = 0;

        u_int32_t prog = mp->rm_call.cb_prog;
        u_int32_t vers = mp->rm_call.cb_vers;
        for (asrv *a = xi->stab.first (); a; a = xi->stab.next (a))
            if (a->hascb () && a->pv.prog == prog) {
                if (a->pv.vers == vers)
                    panic ("asrv_accepterr: prog/vers exists\n");
                // m.acpted_rply.ar_stat = PROC_UNAVAIL;
                else if (m.acpted_rply.ar_stat != PROC_UNAVAIL) {
                    m.acpted_rply.ar_stat = PROG_MISMATCH;
                    if (m.acpted_rply.ar_vers.low > a->pv.vers)
                        m.acpted_rply.ar_vers.low = a->pv.vers;
                    if (m.acpted_rply.ar_vers.high < a->pv.vers)
                        m.acpted_rply.ar_vers.high = a->pv.vers;
                }
            }
        break;
    }
    case PROC_UNAVAIL:
    case GARBAGE_ARGS:
    case SYSTEM_ERR:
        m.acpted_rply.ar_stat = stat;
        break;
    default:
        panic ("asrv_accepterr: bad stat %d\n", stat);
        break;
    }

    xdrsuio x (XDR_ENCODE);
    if (xdr_replymsg (x.xdrp (), &m))
        xi->xh->sendv (x.iov (), x.iovcnt (), addr);
    else
        warn ("asrv_accepterr: xdr_replymsg failed\n");
}
Ejemplo n.º 11
0
static bool_t Svcudp_reply(register SVCXPRT * xprt, struct rpc_msg *msg)
{
  register struct Svcudp_data *su = Su_data(xprt);
  register XDR *xdrs = &(su->su_xdrs);
  register int slen;
  xdrproc_t xdr_proc;
  caddr_t xdr_where;

  xdrs->x_op = XDR_ENCODE;
  XDR_SETPOS(xdrs, 0);
  msg->rm_xid = su->su_xid;

  if(msg->rm_reply.rp_stat == MSG_ACCEPTED && msg->rm_reply.rp_acpt.ar_stat == SUCCESS)
    {
      xdr_proc = msg->acpted_rply.ar_results.proc;
      xdr_where = msg->acpted_rply.ar_results.where;
      msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void;
      msg->acpted_rply.ar_results.where = NULL;

      if(!xdr_replymsg(xdrs, msg) ||
         !SVCAUTH_WRAP(xprt->xp_auth, xdrs, xdr_proc, xdr_where))
        return (FALSE);
    }
  else if(!xdr_replymsg(xdrs, msg))
    {
      return (FALSE);
    }
  slen = (int)XDR_GETPOS(xdrs);

  if(sendto(xprt->XP_SOCK,
            rpc_buffer(xprt),
            slen, 0, (struct sockaddr *)&(xprt->xp_raddr), xprt->xp_addrlen) != slen)
    {
      LogInfo(COMPONENT_DISPATCH, "EAGAIN indicates UDP buffer is full and not"
               " allowed to block. sendto() returned %s", strerror(errno));
      return (FALSE);
    }
  return (TRUE);
}
Ejemplo n.º 12
0
static bool_t
svctcp_reply (SVCXPRT *xprt, struct rpc_msg *msg)
{
  struct tcp_conn *cd = (struct tcp_conn *) (xprt->xp_p1);
  XDR *xdrs = &(cd->xdrs);
  bool_t stat;

  xdrs->x_op = XDR_ENCODE;
  msg->rm_xid = cd->x_id;
  stat = xdr_replymsg (xdrs, msg);
  (void) xdrrec_endofrecord (xdrs, TRUE);
  return stat;
}
Ejemplo n.º 13
0
static bool_t
svcraw_reply(SVCXPRT *xprt, struct rpc_msg *msg)
{
	register struct svcraw_private *srp = svcraw_private;
	register XDR *xdrs;

	if (srp == 0)
		return (FALSE);
	xdrs = &srp->xdr_stream;
	xdrs->x_op = XDR_ENCODE;
	XDR_SETPOS(xdrs, 0);
	if (! xdr_replymsg(xdrs, msg))
	       return (FALSE);
	(void)XDR_GETPOS(xdrs);  /* called just for overhead */
	return (TRUE);
}
Ejemplo n.º 14
0
/*ARGSUSED*/
static bool_t
svc_raw_reply(SVCXPRT *xprt, struct rpc_msg *msg)
{
	struct svc_raw_private *srp;
	XDR *xdrs;

	(void) mutex_lock(&svcraw_lock);
	srp = svc_raw_private;
	if (srp == NULL) {
		(void) mutex_unlock(&svcraw_lock);
		return (FALSE);
	}
	(void) mutex_unlock(&svcraw_lock);

	xdrs = &srp->xdr_stream;
	xdrs->x_op = XDR_ENCODE;
	(void) XDR_SETPOS(xdrs, 0);
	return (xdr_replymsg(xdrs, msg));
}
Ejemplo n.º 15
0
Archivo: asrv.C Proyecto: vonwenm/pbft
static void
asrv_rpc_mismatch (ref<xhinfo> xi, const sockaddr *addr, u_int32_t xid)
{
    rpc_msg m;

    bzero (&m, sizeof (m));
    m.rm_xid = xid;
    m.rm_direction = REPLY;
    m.rm_reply.rp_stat = MSG_DENIED;
    m.rjcted_rply.rj_stat = RPC_MISMATCH;
    m.rjcted_rply.rj_vers.low = RPC_MSG_VERSION;
    m.rjcted_rply.rj_vers.high = RPC_MSG_VERSION;

    xdrsuio x (XDR_ENCODE);
    if (xdr_replymsg (x.xdrp (), &m))
        xi->xh->sendv (x.iov (), x.iovcnt (), addr);
    else
        warn ("asrv_rpc_mismatch: xdr_replymsg failed\n");
}
Ejemplo n.º 16
0
static bool_t svcudp_reply(
    register SVCXPRT *xprt,
    struct rpc_msg *msg)
{
    register struct svcudp_data *su = su_data(xprt);
    register XDR *xdrs = &(su->su_xdrs);
    register int slen;
    register bool_t stat = FALSE;

    xdrproc_t xdr_results;
    caddr_t xdr_location;
    bool_t has_args;

    if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
            msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
        has_args = TRUE;
        xdr_results = msg->acpted_rply.ar_results.proc;
        xdr_location = msg->acpted_rply.ar_results.where;

        msg->acpted_rply.ar_results.proc = xdr_void;
        msg->acpted_rply.ar_results.where = NULL;
    } else
        has_args = FALSE;

    xdrs->x_op = XDR_ENCODE;
    XDR_SETPOS(xdrs, 0);
    msg->rm_xid = su->su_xid;
    if (xdr_replymsg(xdrs, msg) &&
            (!has_args ||
             (SVCAUTH_WRAP(xprt->xp_auth, xdrs, xdr_results, xdr_location)))) {
        slen = (int)XDR_GETPOS(xdrs);
        if (sendto(xprt->xp_sock, rpc_buffer(xprt), slen, 0,
                   (struct sockaddr *)&(xprt->xp_raddr), xprt->xp_addrlen)
                == slen) {
            stat = TRUE;
            if (su->su_cache && slen >= 0) {
                cache_set(xprt, (uint32_t) slen);
            }
        }
    }
    return (stat);
}
Ejemplo n.º 17
0
Archivo: asrv.C Proyecto: vonwenm/pbft
static void
asrv_auth_reject (ref<xhinfo> xi, const sockaddr *addr,
                  u_int32_t xid, auth_stat stat)
{
    rpc_msg m;

    bzero (&m, sizeof (m));
    assert (stat != AUTH_OK);
    m.rm_xid = xid;
    m.rm_direction = REPLY;
    m.rm_reply.rp_stat = MSG_DENIED;
    m.rjcted_rply.rj_stat = AUTH_ERROR;
    m.rjcted_rply.rj_why = stat;

    xdrsuio x (XDR_ENCODE);
    if (xdr_replymsg (x.xdrp (), &m))
        xi->xh->sendv (x.iov (), x.iovcnt (), addr);
    else
        warn ("asrv_auth_reject: xdr_replymsg failed\n");
}
Ejemplo n.º 18
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;
}
Ejemplo n.º 19
0
 /*ARGSUSED*/
static bool
svc_raw_reply(SVCXPRT *xprt, struct svc_req *req, struct rpc_msg *msg)
{
	struct svc_raw_private *srp;
	XDR *xdrs;

	mutex_lock(&svcraw_lock);
	srp = svc_raw_private;
	if (srp == NULL) {
		mutex_unlock(&svcraw_lock);
		return (false);
	}
	mutex_unlock(&svcraw_lock);

	xdrs = &srp->xdr_stream;
	xdrs->x_op = XDR_ENCODE;
	(void)XDR_SETPOS(xdrs, 0);
	if (!xdr_replymsg(xdrs, msg))
		return (false);
	(void)XDR_GETPOS(xdrs);	/* called just for overhead */

	return (true);
}
Ejemplo n.º 20
0
int
rpc_reply_to_xdr (struct rpc_msg *reply, char *dest, size_t len,
                  struct iovec *dst)
{
        XDR xdr;
        int ret = -1;

        GF_VALIDATE_OR_GOTO ("rpc", reply, out);
        GF_VALIDATE_OR_GOTO ("rpc", dest, out);
        GF_VALIDATE_OR_GOTO ("rpc", dst, out);

        xdrmem_create (&xdr, dest, len, XDR_ENCODE);
        if (!xdr_replymsg(&xdr, reply)) {
                gf_log ("rpc", GF_LOG_WARNING, "failed to encode reply msg");
                goto out;
        }

        dst->iov_base = dest;
        dst->iov_len = xdr_encoded_length (xdr);

        ret = 0;
out:
        return ret;
}
Ejemplo n.º 21
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);
}
Ejemplo n.º 22
0
static enum clnt_stat
clnt_dg_call(CLIENT *cl, rpcproc_t proc, xdrproc_t xargs, caddr_t argsp,
	xdrproc_t xresults, caddr_t resultsp, struct timeval utimeout)
{
/* LINTED pointer alignment */
	struct cu_data *cu = (struct cu_data *)cl->cl_private;
	XDR *xdrs;
	int outlen;
	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;
	struct timeval retransmit_time;
	struct timeval poll_time;
	struct timeval startime, curtime;
	struct t_unitdata tu_data;
	int res;			/* result of operations */
	uint32_t x_id;

	if (rpc_fd_lock(dgtbl, cu->cu_fd)) {
		rpc_callerr.re_status = RPC_FAILED;
		rpc_callerr.re_errno = errno;
		rpc_fd_unlock(dgtbl, cu->cu_fd);
		return (RPC_FAILED);
	}

	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;
	retransmit_time = cu->cu_wait;

	tu_data.addr = cu->cu_raddr;

call_again:
	xdrs = &(cu->cu_outxdrs);
	xdrs->x_op = XDR_ENCODE;
	XDR_SETPOS(xdrs, 0);
	/*
	 * Due to little endian byte order, it is necessary to convert to host
	 * format before incrementing xid.
	 */
	/* LINTED pointer cast */
	x_id = ntohl(*(uint32_t *)(cu->cu_outbuf)) + 1;		/* set XID */
	/* LINTED pointer cast */
	*(uint32_t *)cu->cu_outbuf = htonl(x_id);

	if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) {
		if ((!XDR_PUTBYTES(xdrs, cu->cu_outbuf, cu->cu_xdrpos)) ||
		    (!XDR_PUTINT32(xdrs, (int32_t *)&proc)) ||
		    (!AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
		    (!xargs(xdrs, argsp))) {
			rpc_fd_unlock(dgtbl, cu->cu_fd);
			return (rpc_callerr.re_status = RPC_CANTENCODEARGS);
		}
	} else {
/* LINTED pointer alignment */
		uint32_t *u = (uint32_t *)&cu->cu_outbuf[cu->cu_xdrpos];
		IXDR_PUT_U_INT32(u, proc);
		if (!__rpc_gss_wrap(cl->cl_auth, cu->cu_outbuf,
		    ((char *)u) - cu->cu_outbuf, xdrs, xargs, argsp)) {
			rpc_fd_unlock(dgtbl, cu->cu_fd);
			return (rpc_callerr.re_status = RPC_CANTENCODEARGS);
		}
	}
	outlen = (int)XDR_GETPOS(xdrs);

send_again:
	tu_data.udata.buf = cu->cu_outbuf_start;
	tu_data.udata.len = outlen;
	tu_data.opt.len = 0;
	if (t_sndudata(cu->cu_fd, &tu_data) == -1) {
		rpc_callerr.re_terrno = t_errno;
		rpc_callerr.re_errno = errno;
		rpc_fd_unlock(dgtbl, cu->cu_fd);
		return (rpc_callerr.re_status = RPC_CANTSEND);
	}

	/*
	 * Hack to provide rpc-based message passing
	 */
	if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
		rpc_fd_unlock(dgtbl, cu->cu_fd);
		return (rpc_callerr.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 = NULL;
	reply_msg.acpted_rply.ar_results.proc = xdr_void;

	/*
	 * Set polling time so that we don't wait for
	 * longer than specified by the total time to wait,
	 * or the retransmit time.
	 */
	poll_time.tv_sec = timeout.tv_sec - time_waited.tv_sec;
	poll_time.tv_usec = timeout.tv_usec - time_waited.tv_usec;
	while (poll_time.tv_usec < 0) {
		poll_time.tv_usec += 1000000;
		poll_time.tv_sec--;
	}

	if (poll_time.tv_sec < 0 || (poll_time.tv_sec == 0 &&
	    poll_time.tv_usec == 0)) {
		/*
		 * this could happen if time_waited >= timeout
		 */
		rpc_fd_unlock(dgtbl, cu->cu_fd);
		return (rpc_callerr.re_status = RPC_TIMEDOUT);
	}

	if (poll_time.tv_sec > retransmit_time.tv_sec ||
	    (poll_time.tv_sec == retransmit_time.tv_sec &&
	    poll_time.tv_usec > retransmit_time.tv_usec))
		poll_time = retransmit_time;


	for (;;) {

		(void) gettimeofday(&startime, NULL);

		switch (poll(&cu->pfdp, 1,
		    __rpc_timeval_to_msec(&poll_time))) {
		case -1:
			if (errno != EINTR && errno != EAGAIN) {
				rpc_callerr.re_errno = errno;
				rpc_callerr.re_terrno = 0;
				rpc_fd_unlock(dgtbl, cu->cu_fd);
				return (rpc_callerr.re_status = RPC_CANTRECV);
			}
			/*FALLTHROUGH*/

		case 0:
			/*
			 * update time waited
			 */
timeout:			(void) gettimeofday(&curtime, NULL);
			time_waited.tv_sec += curtime.tv_sec - startime.tv_sec;
			time_waited.tv_usec += curtime.tv_usec -
			    startime.tv_usec;
			while (time_waited.tv_usec >= 1000000) {
				time_waited.tv_usec -= 1000000;
				time_waited.tv_sec++;
			}
			while (time_waited.tv_usec < 0) {
				time_waited.tv_usec += 1000000;
				time_waited.tv_sec--;
			}

			/*
			 * decrement time left to poll by same amount
			 */
			poll_time.tv_sec -= curtime.tv_sec - startime.tv_sec;
			poll_time.tv_usec -= curtime.tv_usec - startime.tv_usec;
			while (poll_time.tv_usec >= 1000000) {
				poll_time.tv_usec -= 1000000;
				poll_time.tv_sec++;
			}
			while (poll_time.tv_usec < 0) {
				poll_time.tv_usec += 1000000;
				poll_time.tv_sec--;
			}

			/*
			 * if there's time left to poll, poll again
			 */
			if (poll_time.tv_sec > 0 ||
			    (poll_time.tv_sec == 0 && poll_time.tv_usec > 0))
				continue;

			/*
			 * if there's more time left, retransmit;
			 * otherwise, return timeout error
			 */
			if (time_waited.tv_sec < timeout.tv_sec ||
			    (time_waited.tv_sec == timeout.tv_sec &&
			    time_waited.tv_usec < timeout.tv_usec)) {
				/*
				 * update retransmit_time
				 */
				retransmit_time.tv_usec *= 2;
				retransmit_time.tv_sec *= 2;
				while (retransmit_time.tv_usec >= 1000000) {
					retransmit_time.tv_usec -= 1000000;
					retransmit_time.tv_sec++;
				}
				if (retransmit_time.tv_sec >= RPC_MAX_BACKOFF) {
					retransmit_time.tv_sec =
					    RPC_MAX_BACKOFF;
					retransmit_time.tv_usec = 0;
				}
				/*
				 * redo AUTH_MARSHAL if AUTH_DES or RPCSEC_GSS.
				 */
				if (cl->cl_auth->ah_cred.oa_flavor ==
				    AUTH_DES ||
				    cl->cl_auth->ah_cred.oa_flavor ==
				    RPCSEC_GSS)
					goto call_again;
				else
					goto send_again;
			}
			rpc_fd_unlock(dgtbl, cu->cu_fd);
			return (rpc_callerr.re_status = RPC_TIMEDOUT);

		default:
			break;
		}

		if (cu->pfdp.revents & POLLNVAL || (cu->pfdp.revents == 0)) {
			rpc_callerr.re_status = RPC_CANTRECV;
			/*
			 *	Note:  we're faking errno here because we
			 *	previously would have expected select() to
			 *	return -1 with errno EBADF.  Poll(BA_OS)
			 *	returns 0 and sets the POLLNVAL revents flag
			 *	instead.
			 */
			rpc_callerr.re_errno = errno = EBADF;
			rpc_fd_unlock(dgtbl, cu->cu_fd);
			return (-1);
		}

		/* We have some data now */
		do {
			int moreflag;		/* flag indicating more data */

			moreflag = 0;

			res = t_rcvudata(cu->cu_fd, cu->cu_tr_data, &moreflag);

			if (moreflag & T_MORE) {
				/*
				 * Drop this packet. I aint got any
				 * more space.
				 */
				res = -1;
				/* I should not really be doing this */
				errno = 0;
				/*
				 * XXX: Not really Buffer overflow in the
				 * sense of TLI.
				 */
				t_errno = TBUFOVFLW;
			}
		} while (res < 0 && (t_errno == TSYSERR && errno == EINTR));
		if (res < 0) {
			int err, errnoflag = FALSE;
#ifdef sun
			if (t_errno == TSYSERR && errno == EWOULDBLOCK)
#else
			if (t_errno == TSYSERR && errno == EAGAIN)
#endif
				continue;
			if (t_errno == TLOOK) {
				if ((err = _rcv_unitdata_err(cu)) == 0)
					continue;
				else if (err == 1)
					errnoflag = TRUE;
			} else {
				rpc_callerr.re_terrno = t_errno;
			}
			if (errnoflag == FALSE)
				rpc_callerr.re_errno = errno;
			rpc_fd_unlock(dgtbl, cu->cu_fd);
			return (rpc_callerr.re_status = RPC_CANTRECV);
		}
		if (cu->cu_tr_data->udata.len < (uint_t)sizeof (uint32_t))
			continue;
		/* see if reply transaction id matches sent id */
		/* LINTED pointer alignment */
		if (*((uint32_t *)(cu->cu_inbuf)) !=
		    /* LINTED pointer alignment */
		    *((uint32_t *)(cu->cu_outbuf)))
			goto timeout;
		/* we now assume we have the proper reply */
		break;
	}

	/*
	 * now decode and validate the response
	 */

	xdrmem_create(&reply_xdrs, cu->cu_inbuf,
	    (uint_t)cu->cu_tr_data->udata.len, 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))
			rpc_callerr.re_status = RPC_SUCCESS;
		else
			__seterr_reply(&reply_msg, &(rpc_callerr));

		if (rpc_callerr.re_status == RPC_SUCCESS) {
			if (!AUTH_VALIDATE(cl->cl_auth,
			    &reply_msg.acpted_rply.ar_verf)) {
				rpc_callerr.re_status = RPC_AUTHERROR;
				rpc_callerr.re_why = AUTH_INVALIDRESP;
			} else if (cl->cl_auth->ah_cred.oa_flavor !=
			    RPCSEC_GSS) {
				if (!(*xresults)(&reply_xdrs, resultsp)) {
					if (rpc_callerr.re_status ==
					    RPC_SUCCESS)
						rpc_callerr.re_status =
						    RPC_CANTDECODERES;
				}
			} else if (!__rpc_gss_unwrap(cl->cl_auth, &reply_xdrs,
			    xresults, resultsp)) {
				if (rpc_callerr.re_status == RPC_SUCCESS)
					rpc_callerr.re_status =
					    RPC_CANTDECODERES;
			}
		}		/* end successful completion */
		/*
		 * If unsuccesful AND error is an authentication error
		 * then refresh credentials and try again, else break
		 */
		else if (rpc_callerr.re_status == RPC_AUTHERROR)
			/* maybe our credentials need to be refreshed ... */
			if (nrefreshes-- &&
			    AUTH_REFRESH(cl->cl_auth, &reply_msg))
				goto call_again;
			else
				/*
				 * We are setting rpc_callerr here given that
				 * libnsl is not reentrant thereby
				 * reinitializing the TSD.  If not set here then
				 * success could be returned even though refresh
				 * failed.
				 */
				rpc_callerr.re_status = RPC_AUTHERROR;

		/* 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));
		}
	}	/* end of valid reply message */
	else {
		rpc_callerr.re_status = RPC_CANTDECODERES;

	}
	rpc_fd_unlock(dgtbl, cu->cu_fd);
	return (rpc_callerr.re_status);
}
Ejemplo n.º 23
0
Archivo: svc.c Proyecto: vonwenm/pbft
bool_t  byz_reply(SVCXPRT *xpt, struct rpc_msg *m) { 
  m->rm_xid = xpt->xp_sock;
  return xdr_replymsg(out_stream(xpt), m) ;
}
Ejemplo n.º 24
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;
}
Ejemplo n.º 25
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);
}
Ejemplo n.º 26
0
/*
 * This routine is designed to be able to "ping"
 * a list of hosts and create a list of responding
 * hosts sorted by response time.
 * This must be done without any prior
 * contact with the host - therefore the "ping"
 * must be to a "well-known" address.  The outstanding
 * candidate here is the address of "rpcbind".
 *
 * A response to a ping is no guarantee that the host
 * is running NFS, has a mount daemon, or exports
 * the required filesystem.  If the subsequent
 * mount attempt fails then the host will be marked
 * "ignore" and the host list will be re-pinged
 * (sans the bad host). This process continues
 * until a successful mount is achieved or until
 * there are no hosts left to try.
 */
enum clnt_stat
nfs_cast(struct mapfs *mfs_in, struct mapfs **mfs_out, int timeout)
{
	enum clnt_stat stat;
	AUTH *sys_auth = authsys_create_default();
	XDR xdr_stream;
	register XDR *xdrs = &xdr_stream;
	int outlen;
	int if_inx;
	int tsec;
	int flag;
	int sent, addr_cnt, rcvd, if_cnt;
	fd_set readfds, mask;
	register ulong_t xid;		/* xid - unique per addr */
	register int i;
	struct rpc_msg msg;
	struct timeval t, rcv_timeout;
	char outbuf[UDPMSGSIZE], inbuf[UDPMSGSIZE];
	struct t_unitdata t_udata, t_rdata;
	struct nd_hostserv hs;
	struct nd_addrlist *retaddrs;
	struct transp *tr_head;
	struct transp *trans, *prev_trans;
	struct addrs *a, *prev_addr;
	struct tstamps *ts, *prev_ts;
	NCONF_HANDLE *nc = NULL;
	struct netconfig *nconf;
	struct rlimit rl;
	int dtbsize;
	struct mapfs *mfs;

	/*
	 * For each connectionless transport get a list of
	 * host addresses.  Any single host may have
	 * addresses on several transports.
	 */
	addr_cnt = sent = rcvd = 0;
	tr_head = NULL;
	FD_ZERO(&mask);

	/*
	 * Set the default select size to be the maximum FD_SETSIZE, unless
	 * the current rlimit is lower.
	 */
	dtbsize = FD_SETSIZE;
	if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
		if (rl.rlim_cur < FD_SETSIZE)
			dtbsize = rl.rlim_cur;
	}

	prev_trans = NULL;
	prev_addr = NULL;
	prev_ts = NULL;
	for (mfs = mfs_in; mfs; mfs = mfs->mfs_next) {

		if (trace > 2)
			trace_prt(1, "nfs_cast: host=%s\n", mfs->mfs_host);

		nc = setnetconfig();
		if (nc == NULL) {
			stat = RPC_CANTSEND;
			goto done_broad;
		}
		while (nconf = getnetconfig(nc)) {
			if (!(nconf->nc_flag & NC_VISIBLE) ||
			    nconf->nc_semantics != NC_TPI_CLTS ||
			    (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0))
				continue;
			trans = (struct transp *)malloc(sizeof (*trans));
			if (trans == NULL) {
				syslog(LOG_ERR, "no memory");
				stat = RPC_CANTSEND;
				goto done_broad;
			}
			(void) memset(trans, 0, sizeof (*trans));
			if (tr_head == NULL)
				tr_head = trans;
			else
				prev_trans->tr_next = trans;
			prev_trans = trans;

			trans->tr_fd = t_open(nconf->nc_device, O_RDWR, NULL);
			if (trans->tr_fd < 0) {
				syslog(LOG_ERR, "nfscast: t_open: %s:%m",
					nconf->nc_device);
				stat = RPC_CANTSEND;
				goto done_broad;
			}
			if (t_bind(trans->tr_fd, (struct t_bind *)NULL,
				(struct t_bind *)NULL) < 0) {
				syslog(LOG_ERR, "nfscast: t_bind: %m");
				stat = RPC_CANTSEND;
				goto done_broad;
			}
			trans->tr_taddr =
				/* LINTED pointer alignment */
			(struct t_bind *)t_alloc(trans->tr_fd, T_BIND, T_ADDR);
			if (trans->tr_taddr == (struct t_bind *)NULL) {
				syslog(LOG_ERR, "nfscast: t_alloc: %m");
				stat = RPC_SYSTEMERROR;
				goto done_broad;
			}

			trans->tr_device = nconf->nc_device;
			FD_SET(trans->tr_fd, &mask);

			if_inx = 0;
			hs.h_host = mfs->mfs_host;
			hs.h_serv = "rpcbind";
			if (netdir_getbyname(nconf, &hs, &retaddrs) == ND_OK) {

				/*
				 * If mfs->ignore is previously set for
				 * this map, clear it. Because a host can
				 * have either v6 or v4 address
				 */
				if (mfs->mfs_ignore == 1)
					mfs->mfs_ignore = 0;

				a = (struct addrs *)malloc(sizeof (*a));
				if (a == NULL) {
					syslog(LOG_ERR, "no memory");
					stat = RPC_CANTSEND;
					goto done_broad;
				}
				(void) memset(a, 0, sizeof (*a));
				if (trans->tr_addrs == NULL)
					trans->tr_addrs = a;
				else
					prev_addr->addr_next = a;
				prev_addr = a;
				a->addr_if_tstamps = NULL;
				a->addr_mfs = mfs;
				a->addr_addrs = retaddrs;
				if_cnt = retaddrs->n_cnt;
				while (if_cnt--) {
					ts = (struct tstamps *)
						malloc(sizeof (*ts));
					if (ts == NULL) {
						syslog(LOG_ERR, "no memory");
						stat = RPC_CANTSEND;
						goto done_broad;
					}
					(void) memset(ts, 0, sizeof (*ts));
					ts->ts_penalty = mfs->mfs_penalty;
					if (a->addr_if_tstamps == NULL)
						a->addr_if_tstamps = ts;
					else
						prev_ts->ts_next = ts;
					prev_ts = ts;
					ts->ts_inx = if_inx++;
					addr_cnt++;
				}
				break;
			} else {
				mfs->mfs_ignore = 1;
				if (verbose)
					syslog(LOG_ERR,
				"%s:%s address not known",
				mfs->mfs_host,
				strcmp(nconf->nc_proto, NC_INET)?"IPv6":"IPv4");
			}
		} /* while */

		endnetconfig(nc);
		nc = NULL;
	} /* for */
	if (addr_cnt == 0) {
		syslog(LOG_ERR, "nfscast: couldn't find addresses");
		stat = RPC_CANTSEND;
		goto done_broad;
	}

	(void) gettimeofday(&t, (struct timezone *)0);
	xid = (getpid() ^ t.tv_sec ^ t.tv_usec) & ~0xFF;
	t.tv_usec = 0;

	/* serialize the RPC header */

	msg.rm_direction = CALL;
	msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
	msg.rm_call.cb_prog = RPCBPROG;
	/*
	 * we can not use RPCBVERS here since it doesn't exist in 4.X,
	 * the fix to bug 1139883 has made the 4.X portmapper silent to
	 * version mismatches. This causes the RPC call to the remote
	 * portmapper to simply be ignored if it's not Version 2.
	 */
	msg.rm_call.cb_vers = PMAPVERS;
	msg.rm_call.cb_proc = NULLPROC;
	if (sys_auth == (AUTH *)NULL) {
		stat = RPC_SYSTEMERROR;
		goto done_broad;
	}
	msg.rm_call.cb_cred = sys_auth->ah_cred;
	msg.rm_call.cb_verf = sys_auth->ah_verf;
	xdrmem_create(xdrs, outbuf, sizeof (outbuf), XDR_ENCODE);
	if (! xdr_callmsg(xdrs, &msg)) {
		stat = RPC_CANTENCODEARGS;
		goto done_broad;
	}
	outlen = (int)xdr_getpos(xdrs);
	xdr_destroy(xdrs);

	t_udata.opt.len = 0;
	t_udata.udata.buf = outbuf;
	t_udata.udata.len = outlen;

	/*
	 * Basic loop: send packet to all hosts and wait for response(s).
	 * The response timeout grows larger per iteration.
	 * A unique xid is assigned to each address in order to
	 * correctly match the replies.
	 */
	for (tsec = 4; timeout > 0; tsec *= 2) {

		timeout -= tsec;
		if (timeout <= 0)
			tsec += timeout;

		rcv_timeout.tv_sec = tsec;
		rcv_timeout.tv_usec = 0;

		sent = 0;
		for (trans = tr_head; trans; trans = trans->tr_next) {
			for (a = trans->tr_addrs; a; a = a->addr_next) {
				struct netbuf *if_netbuf =
					a->addr_addrs->n_addrs;
				ts = a->addr_if_tstamps;
				if_cnt = a->addr_addrs->n_cnt;
				while (if_cnt--) {

					/*
					 * xid is the first thing in
					 * preserialized buffer
					 */
					/* LINTED pointer alignment */
					*((ulong_t *)outbuf) =
						htonl(xid + ts->ts_inx);
					(void) gettimeofday(&(ts->ts_timeval),
						(struct timezone *)0);
					/*
					 * Check if already received
					 * from a previous iteration.
					 */
					if (ts->ts_rcvd) {
						sent++;
						ts = ts->ts_next;
						continue;
					}

					t_udata.addr = *if_netbuf++;

					if (t_sndudata(trans->tr_fd,
							&t_udata) == 0) {
						sent++;
					}

					ts = ts->ts_next;
				}
			}
		}
		if (sent == 0) {		/* no packets sent ? */
			stat = RPC_CANTSEND;
			goto done_broad;
		}

		/*
		 * Have sent all the packets.  Now collect the responses...
		 */
		rcvd = 0;
	recv_again:
		msg.acpted_rply.ar_verf = _null_auth;
		msg.acpted_rply.ar_results.proc = xdr_void;
		readfds = mask;

		switch (select(dtbsize, &readfds,
			(fd_set *)NULL, (fd_set *)NULL, &rcv_timeout)) {

		case 0: /* Timed out */
			/*
			 * If we got at least one response in the
			 * last interval, then don't wait for any
			 * more.  In theory we should wait for
			 * the max weighting (penalty) value so
			 * that a very slow server has a chance to
			 * respond but this could take a long time
			 * if the admin has set a high weighting
			 * value.
			 */
			if (rcvd > 0)
				goto done_broad;

			stat = RPC_TIMEDOUT;
			continue;

		case -1:  /* some kind of error */
			if (errno == EINTR)
				goto recv_again;
			syslog(LOG_ERR, "nfscast: select: %m");
			if (rcvd == 0)
				stat = RPC_CANTRECV;
			goto done_broad;

		}  /* end of select results switch */

		for (trans = tr_head; trans; trans = trans->tr_next) {
			if (FD_ISSET(trans->tr_fd, &readfds))
				break;
		}
		if (trans == NULL)
			goto recv_again;

	try_again:
		t_rdata.addr = trans->tr_taddr->addr;
		t_rdata.udata.buf = inbuf;
		t_rdata.udata.maxlen = sizeof (inbuf);
		t_rdata.udata.len = 0;
		t_rdata.opt.len = 0;
		if (t_rcvudata(trans->tr_fd, &t_rdata, &flag) < 0) {
			if (errno == EINTR)
				goto try_again;
			syslog(LOG_ERR, "nfscast: t_rcvudata: %s:%m",
				trans->tr_device);
			stat = RPC_CANTRECV;
			continue;
		}
		if (t_rdata.udata.len < sizeof (ulong_t))
			goto recv_again;
		if (flag & T_MORE) {
			syslog(LOG_ERR,
				"nfscast: t_rcvudata: %s: buffer overflow",
				trans->tr_device);
			goto recv_again;
		}

		/*
		 * see if reply transaction id matches sent id.
		 * If so, decode the results.
		 * Note: received addr is ignored, it could be
		 * different from the send addr if the host has
		 * more than one addr.
		 */
		xdrmem_create(xdrs, inbuf, (uint_t)t_rdata.udata.len,
								XDR_DECODE);
		if (xdr_replymsg(xdrs, &msg)) {
		    if (msg.rm_reply.rp_stat == MSG_ACCEPTED &&
			(msg.rm_xid & ~0xFF) == xid) {
			struct addrs *curr_addr;

			i = msg.rm_xid & 0xFF;
			for (curr_addr = trans->tr_addrs; curr_addr;
			    curr_addr = curr_addr->addr_next) {
			    for (ts = curr_addr->addr_if_tstamps; ts;
				ts = ts->ts_next)
				if (ts->ts_inx == i && !ts->ts_rcvd) {
					ts->ts_rcvd = 1;
					calc_resp_time(&ts->ts_timeval);
					stat = RPC_SUCCESS;
					rcvd++;
					break;
				}
			}
		    } /* otherwise, we just ignore the errors ... */
		}
		xdrs->x_op = XDR_FREE;
		msg.acpted_rply.ar_results.proc = xdr_void;
		(void) xdr_replymsg(xdrs, &msg);
		XDR_DESTROY(xdrs);
		if (rcvd == sent)
			goto done_broad;
		else
			goto recv_again;
	}
	if (!rcvd)
		stat = RPC_TIMEDOUT;

done_broad:
	if (rcvd) {
		*mfs_out = sort_responses(tr_head);
		stat = RPC_SUCCESS;
	}
	if (nc)
		endnetconfig(nc);
	free_transports(tr_head);
	AUTH_DESTROY(sys_auth);
	return (stat);
}
Ejemplo n.º 27
0
/* ARGSUSED */
static enum clnt_stat
clnt_door_call(CLIENT *cl, rpcproc_t proc, xdrproc_t xargs, caddr_t argsp,
	xdrproc_t xresults, caddr_t resultsp, struct timeval utimeout)
{
/* LINTED pointer alignment */
	struct cu_data	*cu = (struct cu_data *)cl->cl_private;
	XDR 		xdrs;
	door_arg_t	params;
	char		*outbuf_ref;
	struct rpc_msg	reply_msg;
	bool_t		need_to_unmap;
	int		nrefreshes = 2;	/* number of times to refresh cred */

	rpc_callerr.re_errno = 0;
	rpc_callerr.re_terrno = 0;

	if ((params.rbuf = alloca(cu->cu_sendsz)) == NULL) {
		rpc_callerr.re_terrno = 0;
		rpc_callerr.re_errno = errno;
		return (rpc_callerr.re_status = RPC_SYSTEMERROR);
	}
	outbuf_ref = params.rbuf;
	params.rsize = cu->cu_sendsz;
	if ((params.data_ptr = alloca(cu->cu_sendsz)) == NULL) {
		rpc_callerr.re_terrno = 0;
		rpc_callerr.re_errno = errno;
		return (rpc_callerr.re_status = RPC_SYSTEMERROR);
	}

call_again:
	xdrmem_create(&xdrs, params.data_ptr, cu->cu_sendsz, XDR_ENCODE);
/* LINTED pointer alignment */
	(*(uint32_t *)cu->cu_header)++;	/* increment XID */
	(void) memcpy(params.data_ptr, cu->cu_header, cu->cu_xdrpos);
	XDR_SETPOS(&xdrs, cu->cu_xdrpos);

	if ((!XDR_PUTINT32(&xdrs, (int32_t *)&proc)) ||
				(!AUTH_MARSHALL(cl->cl_auth, &xdrs)) ||
					(!(*xargs)(&xdrs, argsp))) {
		return (rpc_callerr.re_status = RPC_CANTENCODEARGS);
	}
	params.data_size = (int)XDR_GETPOS(&xdrs);

	params.desc_ptr = NULL;
	params.desc_num = 0;
	if (door_call(cu->cu_fd, &params) < 0) {
		rpc_callerr.re_errno = errno;
		return (rpc_callerr.re_status = RPC_CANTSEND);
	}

	if (params.rbuf == NULL || params.rsize == 0) {
		return (rpc_callerr.re_status = RPC_FAILED);
	}
	need_to_unmap = (params.rbuf != outbuf_ref);

/* LINTED pointer alignment */
	if (*(uint32_t *)params.rbuf != *(uint32_t *)cu->cu_header) {
		rpc_callerr.re_status = RPC_CANTDECODERES;
		goto done;
	}

	xdrmem_create(&xdrs, params.rbuf, params.rsize, XDR_DECODE);
	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, &reply_msg)) {
		if (reply_msg.rm_reply.rp_stat == MSG_ACCEPTED &&
				reply_msg.acpted_rply.ar_stat == SUCCESS)
			rpc_callerr.re_status = RPC_SUCCESS;
		else
			__seterr_reply(&reply_msg, &rpc_callerr);

		if (rpc_callerr.re_status == RPC_SUCCESS) {
			if (!AUTH_VALIDATE(cl->cl_auth,
					    &reply_msg.acpted_rply.ar_verf)) {
				rpc_callerr.re_status = RPC_AUTHERROR;
				rpc_callerr.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));
			}
		}
		/*
		 * If unsuccesful AND error is an authentication error
		 * then refresh credentials and try again, else break
		 */
		else if (rpc_callerr.re_status == RPC_AUTHERROR) {
			/*
			 * maybe our credentials need to be refreshed ...
			 */
			if (nrefreshes-- &&
			    AUTH_REFRESH(cl->cl_auth, &reply_msg)) {
				if (need_to_unmap)
					(void) munmap(params.rbuf,
								params.rsize);
				goto call_again;
			} else
				/*
				 * We are setting rpc_callerr here given that
				 * libnsl is not reentrant thereby
				 * reinitializing the TSD.  If not set here then
				 * success could be returned even though refresh
				 * failed.
				 */
				rpc_callerr.re_status = RPC_AUTHERROR;
		}
	} else
		rpc_callerr.re_status = RPC_CANTDECODERES;

done:
	if (need_to_unmap)
		(void) munmap(params.rbuf, params.rsize);
	return (rpc_callerr.re_status);
}
Ejemplo n.º 28
0
enum clnt_stat 
clnt_broadcast(u_long prog,	/* program number */
    u_long vers,		/* version number */
    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 */
    resultproc_t eachresult)	/* call with each result obtained */
{
	enum clnt_stat stat;
	AUTH *unix_auth;
	XDR xdr_stream;
	XDR *xdrs = &xdr_stream;
	int outlen, inlen, nets;
	socklen_t fromlen;
	int sock = -1;
	int on = 1;
	struct pollfd pfd[1];
	int i;
	int timo;
	bool_t done = FALSE;
	u_long xid;
	u_long port;
	struct in_addr *addrs = NULL;
	struct sockaddr_in baddr, raddr; /* broadcast and response addresses */
	struct rmtcallargs a;
	struct rmtcallres r;
	struct rpc_msg msg;
	char outbuf[MAX_BROADCAST_SIZE], inbuf[UDPMSGSIZE];

	if ((unix_auth = authunix_create_default()) == NULL) {
		stat = RPC_AUTHERROR;
		goto done_broad;
	}

	/*
	 * initialization: create a socket, a broadcast address, and
	 * preserialize the arguments into a send buffer.
	 */
	if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
		stat = RPC_CANTSEND;
		goto done_broad;
	}
#ifdef SO_BROADCAST
	if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
		stat = RPC_CANTSEND;
		goto done_broad;
	}
#endif /* def SO_BROADCAST */

	pfd[0].fd = sock;
	pfd[0].events = POLLIN;

	nets = newgetbroadcastnets(&addrs);
	if (nets == 0) {
		stat = RPC_CANTSEND;
		goto done_broad;
	}

	memset(&baddr, 0, sizeof (baddr));
	baddr.sin_len = sizeof(struct sockaddr_in);
	baddr.sin_family = AF_INET;
	baddr.sin_port = htons(PMAPPORT);
	baddr.sin_addr.s_addr = htonl(INADDR_ANY);
	msg.rm_xid = xid = arc4random();
	msg.rm_direction = CALL;
	msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
	msg.rm_call.cb_prog = PMAPPROG;
	msg.rm_call.cb_vers = PMAPVERS;
	msg.rm_call.cb_proc = PMAPPROC_CALLIT;
	msg.rm_call.cb_cred = unix_auth->ah_cred;
	msg.rm_call.cb_verf = unix_auth->ah_verf;
	a.prog = prog;
	a.vers = vers;
	a.proc = proc;
	a.xdr_args = xargs;
	a.args_ptr = argsp;
	r.port_ptr = &port;
	r.xdr_results = xresults;
	r.results_ptr = resultsp;
	xdrmem_create(xdrs, outbuf, MAX_BROADCAST_SIZE, XDR_ENCODE);
	if (!xdr_callmsg(xdrs, &msg) || !xdr_rmtcall_args(xdrs, &a)) {
		stat = RPC_CANTENCODEARGS;
		goto done_broad;
	}
	outlen = (int)xdr_getpos(xdrs);
	xdr_destroy(xdrs);

	/*
	 * Basic loop: broadcast a packet and wait a while for response(s).
	 * The response timeout grows larger per iteration.
	 *
	 * XXX This will loop about 5 times the stop. If there are
	 * lots of signals being received by the process it will quit
	 * send them all in one quick burst, not paying attention to
	 * the intended function of sending them slowly over half a
	 * minute or so
	 */
	for (timo = 4000; timo <= 14000; timo += 2000) {
		for (i = 0; i < nets; i++) {
			baddr.sin_addr = addrs[i];
			if (sendto(sock, outbuf, outlen, 0,
			    (struct sockaddr *)&baddr,
			    sizeof (struct sockaddr)) != outlen) {
				stat = RPC_CANTSEND;
				goto done_broad;
			}
		}
		if (eachresult == NULL) {
			stat = RPC_SUCCESS;
			goto done_broad;
		}
	recv_again:
		msg.acpted_rply.ar_verf = _null_auth;
		msg.acpted_rply.ar_results.where = (caddr_t)&r;
		msg.acpted_rply.ar_results.proc = xdr_rmtcallres;

		switch (poll(pfd, 1, timo)) {
		case 0:  /* timed out */
			stat = RPC_TIMEDOUT;
			continue;
		case 1:
			if (pfd[0].revents & POLLNVAL)
				errno = EBADF;
			else if (pfd[0].revents & POLLERR)
				errno = EIO;
			else
				break;
			/* FALLTHROUGH */
		case -1:  /* some kind of error */
			if (errno == EINTR)
				goto recv_again;
			stat = RPC_CANTRECV;
			goto done_broad;
		}
	try_again:
		fromlen = sizeof(struct sockaddr);
		inlen = recvfrom(sock, inbuf, UDPMSGSIZE, 0,
		    (struct sockaddr *)&raddr, &fromlen);
		if (inlen < 0) {
			if (errno == EINTR)
				goto try_again;
			stat = RPC_CANTRECV;
			goto done_broad;
		}
		if (inlen < sizeof(u_int32_t))
			goto recv_again;
		/*
		 * see if reply transaction id matches sent id.
		 * If so, decode the results.
		 */
		xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE);
		if (xdr_replymsg(xdrs, &msg)) {
			if ((msg.rm_xid == xid) &&
			    (msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
			    (msg.acpted_rply.ar_stat == SUCCESS)) {
				raddr.sin_port = htons((u_short)port);
				done = (*eachresult)(resultsp, &raddr);
			}
			/* otherwise, we just ignore the errors ... */
		}
		xdrs->x_op = XDR_FREE;
		msg.acpted_rply.ar_results.proc = xdr_void;
		(void)xdr_replymsg(xdrs, &msg);
		(void)(*xresults)(xdrs, resultsp);
		xdr_destroy(xdrs);
		if (done) {
			stat = RPC_SUCCESS;
			goto done_broad;
		} else {
			goto recv_again;
		}
	}
done_broad:
	if (addrs)
		free(addrs);
	if (sock >= 0)
		(void)close(sock);
	if (unix_auth != NULL)
		AUTH_DESTROY(unix_auth);
	return (stat);
}
Ejemplo n.º 29
0
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);
}
Ejemplo n.º 30
0
enum clnt_stat 
clnt_broadcast(
	unsigned long		prog,		/* program number */
	unsigned long		vers,		/* version number */
	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 */
	resultproc_t	eachresult)	/* call with each result obtained */
{
	enum clnt_stat stat;
	AUTH *unix_auth = authunix_create_default();
	XDR xdr_stream;
	register XDR *xdrs = &xdr_stream;
	int outlen, nets;
	ssize_t inlen;
	socklen_t fromlen;
	register int sock;
	int on = 1;
#ifdef FD_SETSIZE
	fd_set mask;
	fd_set readfds;
#else
	int readfds;
	register int mask;
#endif /* def FD_SETSIZE */
	register int i;
	bool_t done = FALSE;
	register unsigned long xid;
	unsigned long port;
	struct in_addr addrs[20];
	struct sockaddr_in baddr, raddr; /* broadcast and response addresses */
	struct rmtcallargs a;
	struct rmtcallres r;
	struct rpc_msg msg;
	struct timeval t; 
	char outbuf[MAX_BROADCAST_SIZE], inbuf[UDPMSGSIZE];

	/*
	 * initialization: create a socket, a broadcast address, and
	 * preserialize the arguments into a send buffer.
	 */
	if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
		perror("Cannot create socket for broadcast rpc");
		stat = RPC_CANTSEND;
		goto done_broad;
	}
#ifdef SO_BROADCAST
	if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
		perror("Cannot set socket option SO_BROADCAST");
		stat = RPC_CANTSEND;
		goto done_broad;
	}
#endif /* def SO_BROADCAST */
#ifdef FD_SETSIZE
	FD_ZERO(&mask);
	FD_SET(sock, &mask);
#else
	mask = (1 << sock);
#endif /* def FD_SETSIZE */
	nets = getbroadcastnets(addrs, sock, inbuf);
	bzero((char *)&baddr, sizeof (baddr));
	baddr.sin_family = AF_INET;
	baddr.sin_port = htons(PMAPPORT);
	baddr.sin_addr.s_addr = htonl(INADDR_ANY);
/*	baddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); */
	(void)gettimeofday(&t, NULL);
	msg.rm_xid = xid = getpid() ^ t.tv_sec ^ t.tv_usec;
	t.tv_usec = 0;
	msg.rm_direction = CALL;
	msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
	msg.rm_call.cb_prog = PMAPPROG;
	msg.rm_call.cb_vers = PMAPVERS;
	msg.rm_call.cb_proc = PMAPPROC_CALLIT;
	msg.rm_call.cb_cred = unix_auth->ah_cred;
	msg.rm_call.cb_verf = unix_auth->ah_verf;
	a.prog = prog;
	a.vers = vers;
	a.proc = proc;
	a.xdr_args = xargs;
	a.args_ptr = argsp;
	r.port_ptr = &port;
	r.xdr_results = xresults;
	r.results_ptr = resultsp;
	xdrmem_create(xdrs, outbuf, MAX_BROADCAST_SIZE, XDR_ENCODE);
	if ((! xdr_callmsg(xdrs, &msg)) || (! xdr_rmtcall_args(xdrs, &a))) {
		stat = RPC_CANTENCODEARGS;
		goto done_broad;
	}
	outlen = (int)xdr_getpos(xdrs);
	xdr_destroy(xdrs);
	/*
	 * Basic loop: broadcast a packet and wait a while for response(s).
	 * The response timeout grows larger per iteration.
	 */
	for (t.tv_sec = 4; t.tv_sec <= 14; t.tv_sec += 2) {
		for (i = 0; i < nets; i++) {
			baddr.sin_addr = addrs[i];
			if (sendto(sock, outbuf, outlen, 0,
				(struct sockaddr *)&baddr,
				sizeof (struct sockaddr)) != (ssize_t)outlen) {
				perror("Cannot send broadcast packet");
				stat = RPC_CANTSEND;
				goto done_broad;
			}
		}
		if (eachresult == NULL) {
			stat = RPC_SUCCESS;
			goto done_broad;
		}
	recv_again:
		msg.acpted_rply.ar_verf = _null_auth;
		msg.acpted_rply.ar_results.where = (char*)&r;
                msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_rmtcallres;
		readfds = mask;
		{
		    struct timeval	tmp = t;

		    switch (select(sock+1, &readfds, NULL, 
				   NULL, &tmp)) {

		    case 0:  /* timed out */
			    stat = RPC_TIMEDOUT;
			    continue;

		    case -1:  /* some kind of error */
			    if (errno == EINTR)
				    goto recv_again;
			    perror("Broadcast select problem");
			    stat = RPC_CANTRECV;
			    goto done_broad;

		    }  /* end of select results switch */
		}  /* end of temporary timeout variable */
	try_again:
		fromlen = (socklen_t)sizeof(struct sockaddr);
		inlen = recvfrom(sock, inbuf, UDPMSGSIZE, 0,
			(struct sockaddr *)&raddr, &fromlen);
		if (inlen < 0) {
			if (errno == EINTR)
				goto try_again;
			perror("Cannot receive reply to broadcast");
			stat = RPC_CANTRECV;
			goto done_broad;
		}
		if (inlen < sizeof(uint32_t))
			goto recv_again;
		/*
		 * see if reply transaction id matches sent id.
		 * If so, decode the results.
		 */
		xdrmem_create(xdrs, inbuf, (unsigned)inlen, XDR_DECODE);
		if (xdr_replymsg(xdrs, &msg)) {
			if ((msg.rm_xid == xid) &&
				(msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
				(msg.acpted_rply.ar_stat == SUCCESS)) {

				raddr.sin_port = htons((unsigned short)port);
				done = (*eachresult)(resultsp, &raddr);
			}
			/* otherwise, we just ignore the errors ... */
		} else {
#ifdef notdef
			/* some kind of deserialization problem ... */
			if (msg.rm_xid == xid)
				(void)fprintf(stderr, "Broadcast deserialization problem");
			/* otherwise, just random garbage */
#endif
		}
		xdrs->x_op = XDR_FREE;
		msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
		(void)xdr_replymsg(xdrs, &msg);
		(void)(*xresults)(xdrs, resultsp);
		xdr_destroy(xdrs);
		if (done) {
			stat = RPC_SUCCESS;
			goto done_broad;
		} else {
			goto recv_again;
		}
	}
done_broad:
	(void)close(sock);
	AUTH_DESTROY(unix_auth);
	return (stat);
}