Exemple #1
0
int
rpc_request_to_xdr(struct rpc_msg *request, char *dest, size_t len,
                   struct iovec *dst)
{
    XDR xdr;
    int ret = -1;

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

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

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

    ret = 0;

out:
    return ret;
}
Exemple #2
0
static bool_t
svcudp_recv(
	register SVCXPRT *xprt,
	struct rpc_msg *msg)
{
	register struct svcudp_data *su = su_data(xprt);
	register XDR *xdrs = &(su->su_xdrs);
	register ssize_t rlen;
	char *reply;
	unsigned long replylen;
	socklen_t len;

    again:
	len = xprt->xp_addrlen = sizeof(struct sockaddr_in);
	rlen = recvfrom(xprt->xp_sock, rpc_buffer(xprt), (int) su->su_iosz,
	    0, (struct sockaddr *)&(xprt->xp_raddr), &len);
	if (rlen == -1 && errno == EINTR)
		goto again;
	if (rlen < 4*sizeof(uint32_t))
		return (FALSE);
	xprt->xp_addrlen = len;
	xdrs->x_op = XDR_DECODE;
	XDR_SETPOS(xdrs, 0);
	if (! xdr_callmsg(xdrs, msg))
		return (FALSE);
	su->su_xid = msg->rm_xid;
	if (su->su_cache != NULL) {
		if (cache_get(xprt, msg, &reply, &replylen)) {
			(void) sendto(xprt->xp_sock, reply, replylen, 0,
			  (struct sockaddr *) &xprt->xp_raddr, xprt->xp_addrlen);
			return (TRUE);
		}
	}
	return (TRUE);
}
static bool_t Svcudp_recv(register SVCXPRT * xprt, struct rpc_msg *msg)
{
  register struct Svcudp_data *su = Su_data(xprt);
  register XDR *xdrs = &(su->su_xdrs);
  register int rlen;

 again:
  xprt->xp_addrlen = sizeof(struct sockaddr_in);
#ifdef _FREEBSD
  rlen = recvfrom(xprt->xp_fd, rpc_buffer(xprt), (int)su->su_iosz,
                  0, (struct sockaddr *)&(xprt->xp_raddr), &(xprt->xp_addrlen));
#else
  rlen = recvfrom(xprt->xp_sock, rpc_buffer(xprt), (int)su->su_iosz,
                  0, (struct sockaddr *)&(xprt->xp_raddr), &(xprt->xp_addrlen));
#endif

  if(rlen == -1 && errno == EINTR)
    goto again;

  if(rlen == -1 || rlen < 4 * sizeof(u_int32_t))
    return (FALSE);

  xdrs->x_op = XDR_DECODE;

  XDR_SETPOS(xdrs, 0);

  if(!xdr_callmsg(xdrs, msg))
    return (FALSE);

  su->su_xid = msg->rm_xid;

  return (TRUE);
}
Exemple #4
0
bool_t byz_recv(SVCXPRT *xpt, struct rpc_msg *m) {  
  if (!xdr_callmsg(in_stream(xpt), m))
    return FALSE;
  
  /* Save xid to put in reply */
  xpt->xp_sock = m->rm_xid;  
  return TRUE;
}
Exemple #5
0
static bool_t
svc_dg_recv(SVCXPRT *xprt, struct rpc_msg *msg)
{
	struct svc_dg_data *su;
	XDR *xdrs;
	char *reply;
	struct sockaddr_storage ss;
	socklen_t alen;
	size_t replylen;
	ssize_t rlen;

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

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

again:
	alen = sizeof (struct sockaddr_storage);
	rlen = recvfrom(xprt->xp_fd, rpc_buffer(xprt), su->su_iosz, 0,
	    (struct sockaddr *)(void *)&ss, &alen);
	if (rlen == -1 && errno == EINTR)
		goto again;
	if (rlen == -1 || (rlen < (ssize_t)(4 * sizeof (u_int32_t))))
		return (FALSE);
	if (xprt->xp_rtaddr.len < alen) {
		if (xprt->xp_rtaddr.len != 0)
			mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.len);
		xprt->xp_rtaddr.buf = mem_alloc(alen);
		xprt->xp_rtaddr.len = alen;
	}
	memcpy(xprt->xp_rtaddr.buf, &ss, alen);
#ifdef PORTMAP
	if (ss.ss_family == AF_INET) {
		xprt->xp_raddr = *(struct sockaddr_in *)xprt->xp_rtaddr.buf;
		xprt->xp_addrlen = sizeof (struct sockaddr_in);
	}
#endif
	xdrs->x_op = XDR_DECODE;
	XDR_SETPOS(xdrs, 0);
	if (! xdr_callmsg(xdrs, msg)) {
		return (FALSE);
	}
	su->su_xid = msg->rm_xid;
	if (su->su_cache != NULL) {
		if (cache_get(xprt, msg, &reply, &replylen)) {
			(void)sendto(xprt->xp_fd, reply, replylen, 0,
			    (struct sockaddr *)(void *)&ss, alen);
			return (FALSE);
		}
	}
	return (TRUE);
}
Exemple #6
0
static bool_t
svcudp_recv(
	SVCXPRT *xprt,
	struct rpc_msg *msg)
{
        struct msghdr dummy;
	struct iovec dummy_iov[1];
	struct svcudp_data *su = su_data(xprt);
	XDR *xdrs = &su->su_xdrs;
	int rlen;
	char *reply;
	uint32_t replylen;
	socklen_t addrlen;

    again:
	memset(&dummy, 0, sizeof(dummy));
	dummy_iov[0].iov_base = rpc_buffer(xprt);
	dummy_iov[0].iov_len = (int) su->su_iosz;
	dummy.msg_iov = dummy_iov;
	dummy.msg_iovlen = 1;
	dummy.msg_namelen = xprt->xp_laddrlen = sizeof(struct sockaddr_in);
	dummy.msg_name = (char *) &xprt->xp_laddr;
	rlen = recvmsg(xprt->xp_sock, &dummy, MSG_PEEK);
	if (rlen == -1) {
	     if (errno == EINTR)
		  goto again;
	     else
		  return (FALSE);
	}

	addrlen = sizeof(struct sockaddr_in);
	rlen = recvfrom(xprt->xp_sock, rpc_buffer(xprt), (int) su->su_iosz,
	    0, (struct sockaddr *)&(xprt->xp_raddr), &addrlen);
	if (rlen == -1 && errno == EINTR)
		goto again;
	if (rlen < (int) (4*sizeof(uint32_t)))
		return (FALSE);
	xprt->xp_addrlen = addrlen;
	xdrs->x_op = XDR_DECODE;
	XDR_SETPOS(xdrs, 0);
	if (! xdr_callmsg(xdrs, msg))
		return (FALSE);
	su->su_xid = msg->rm_xid;
	if (su->su_cache != NULL) {
		if (cache_get(xprt, msg, &reply, &replylen)) {
			(void) sendto(xprt->xp_sock, reply, (int) replylen, 0,
			  (struct sockaddr *) &xprt->xp_raddr, xprt->xp_addrlen);
			return (TRUE);
		}
	}
	return (TRUE);
}
static bool_t Svctcp_recv(SVCXPRT * xprt, register struct rpc_msg *msg)
{
  register struct tcp_conn *cd = (struct tcp_conn *)(xprt->xp_p1);
  register XDR *xdrs = &(cd->xdrs);

  xdrs->x_op = XDR_DECODE;
  (void)xdrrec_skiprecord(xdrs);
  if(xdr_callmsg(xdrs, msg))
    {
      cd->x_id = msg->rm_xid;
      return (TRUE);
    }
  return (FALSE);
}
Exemple #8
0
static bool_t
svcraw_recv(SVCXPRT *xprt, struct rpc_msg *msg)
{
	register struct svcraw_private *srp = svcraw_private;
	register XDR *xdrs;

	if (srp == 0)
		return (0);
	xdrs = &srp->xdr_stream;
	xdrs->x_op = XDR_DECODE;
	XDR_SETPOS(xdrs, 0);
	if (! xdr_callmsg(xdrs, msg))
	       return (FALSE);
	return (TRUE);
}
static bool_t
svctcp_recv (SVCXPRT *xprt, struct rpc_msg *msg)
{
  struct tcp_conn *cd = (struct tcp_conn *) (xprt->xp_p1);
  XDR *xdrs = &(cd->xdrs);

  xdrs->x_op = XDR_DECODE;
  (void) xdrrec_skiprecord (xdrs);
  if (xdr_callmsg (xdrs, msg))
    {
      cd->x_id = msg->rm_xid;
      return TRUE;
    }
  cd->strm_stat = XPRT_DIED;	/* XXXX */
  return FALSE;
}
Exemple #10
0
struct rpc_pdu *rpc_allocate_pdu(struct rpc_context *rpc, int program, int version, int procedure, rpc_cb cb, void *private_data, xdrproc_t xdr_decode_fn, int xdr_decode_bufsize)
{
	struct rpc_pdu *pdu;
	struct rpc_msg msg;

	if (rpc == NULL) {
		printf("trying to allocate rpc pdu on NULL context\n");
		return NULL;
	}

	pdu = malloc(sizeof(struct rpc_pdu));
	if (pdu == NULL) {
		printf("Failed to allocate pdu structure\n");
		return NULL;
	}
	bzero(pdu, sizeof(struct rpc_pdu));
	pdu->xid                = rpc->xid++;
	pdu->cb                 = cb;
	pdu->private_data       = private_data;
	pdu->xdr_decode_fn      = xdr_decode_fn;
	pdu->xdr_decode_bufsize = xdr_decode_bufsize;

	xdrmem_create(&pdu->xdr, rpc->encodebuf, rpc->encodebuflen, XDR_ENCODE);
	xdr_setpos(&pdu->xdr, 4); /* skip past the record marker */

	bzero(&msg, sizeof(struct rpc_msg));
	msg.rm_xid = pdu->xid;
        msg.rm_direction = CALL;
	msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
	msg.rm_call.cb_prog = program;
	msg.rm_call.cb_vers = version;
	msg.rm_call.cb_proc = procedure;
	msg.rm_call.cb_cred = rpc->auth->ah_cred;
	msg.rm_call.cb_verf = rpc->auth->ah_verf;

	if (xdr_callmsg(&pdu->xdr, &msg) == 0) {
		printf("xdr_callmsg failed\n");
		xdr_destroy(&pdu->xdr);
		free(pdu);
		return NULL;
	}

	return pdu;
}
Exemple #11
0
/*ARGSUSED*/
static bool_t
svc_raw_recv(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_DECODE;
	(void) XDR_SETPOS(xdrs, 0);
	return (xdr_callmsg(xdrs, msg));
}
Exemple #12
0
/* Decodes the XDR format in msgbuf into rpc_msg.
 * The remaining payload is returned into payload.
 */
int
xdr_to_rpc_call (char *msgbuf, size_t len, struct rpc_msg *call,
                 struct iovec *payload, char *credbytes, char *verfbytes)
{
        XDR                     xdr;
        char                    opaquebytes[MAX_AUTH_BYTES];
        struct opaque_auth      *oa = NULL;
        int ret = -1;

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

        memset (call, 0, sizeof (*call));

        oa = &call->rm_call.cb_cred;
        if (!credbytes)
                oa->oa_base = opaquebytes;
        else
                oa->oa_base = credbytes;

        oa = &call->rm_call.cb_verf;
        if (!verfbytes)
                oa->oa_base = opaquebytes;
        else
                oa->oa_base = verfbytes;

        xdrmem_create (&xdr, msgbuf, len, XDR_DECODE);
        if (!xdr_callmsg (&xdr, call)) {
                gf_log ("rpc", GF_LOG_WARNING, "failed to decode call 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;
}
static bool_t
svcunix_recv (SVCXPRT *xprt, struct rpc_msg *msg)
{
  struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
  XDR *xdrs = &(cd->xdrs);

  xdrs->x_op = XDR_DECODE;
  xdrrec_skiprecord (xdrs);
  if (xdr_callmsg (xdrs, msg))
    {
      cd->x_id = msg->rm_xid;
      /* set up verifiers */
#ifdef SCM_CREDENTIALS
      msg->rm_call.cb_verf.oa_flavor = AUTH_UNIX;
      msg->rm_call.cb_verf.oa_base = (caddr_t) &cm;
      msg->rm_call.cb_verf.oa_length = sizeof (cm);
#endif
      return TRUE;
    }
  cd->strm_stat = XPRT_DIED;	/* XXXX */
  return FALSE;
}
Exemple #14
0
 /*ARGSUSED*/
static bool
svc_raw_recv(SVCXPRT *xprt, struct svc_req *req)
{
	struct rpc_msg *msg = req->rq_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_DECODE;
	(void)XDR_SETPOS(xdrs, 0);
	if (!xdr_callmsg(xdrs, msg))
		return (false);

	return (true);
}
Exemple #15
0
static bool_t
svc_vc_backchannel_recv(SVCXPRT *xprt, struct rpc_msg *msg,
    struct sockaddr **addrp, struct mbuf **mp)
{
	struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1;
	struct ct_data *ct;
	struct mbuf *m;
	XDR xdrs;

	sx_xlock(&xprt->xp_lock);
	ct = (struct ct_data *)xprt->xp_p2;
	if (ct == NULL) {
		sx_xunlock(&xprt->xp_lock);
		return (FALSE);
	}
	mtx_lock(&ct->ct_lock);
	m = cd->mreq;
	if (m == NULL) {
		xprt_inactive_self(xprt);
		mtx_unlock(&ct->ct_lock);
		sx_xunlock(&xprt->xp_lock);
		return (FALSE);
	}
	cd->mreq = m->m_nextpkt;
	mtx_unlock(&ct->ct_lock);
	sx_xunlock(&xprt->xp_lock);

	xdrmbuf_create(&xdrs, m, XDR_DECODE);
	if (! xdr_callmsg(&xdrs, msg)) {
		XDR_DESTROY(&xdrs);
		return (FALSE);
	}
	*addrp = NULL;
	*mp = xdrmbuf_getall(&xdrs);
	XDR_DESTROY(&xdrs);
	return (TRUE);
}
Exemple #16
0
static bool_t
svc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg,
    struct sockaddr **addrp, struct mbuf **mp)
{
	struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1;
	struct uio uio;
	struct mbuf *m;
	struct socket* so = xprt->xp_socket;
	XDR xdrs;
	int error, rcvflag;
	uint32_t xid_plus_direction[2];

	/*
	 * Serialise access to the socket and our own record parsing
	 * state.
	 */
	sx_xlock(&xprt->xp_lock);

	for (;;) {
		/* If we have no request ready, check pending queue. */
		while (cd->mpending &&
		    (cd->mreq == NULL || cd->resid != 0 || !cd->eor)) {
			if (!svc_vc_process_pending(xprt))
				break;
		}

		/* Process and return complete request in cd->mreq. */
		if (cd->mreq != NULL && cd->resid == 0 && cd->eor) {

			/*
			 * Now, check for a backchannel reply.
			 * The XID is in the first uint32_t of the reply
			 * and the message direction is the second one.
			 */
			if ((cd->mreq->m_len >= sizeof(xid_plus_direction) ||
			    m_length(cd->mreq, NULL) >=
			    sizeof(xid_plus_direction)) &&
			    xprt->xp_p2 != NULL) {
				m_copydata(cd->mreq, 0,
				    sizeof(xid_plus_direction),
				    (char *)xid_plus_direction);
				xid_plus_direction[0] =
				    ntohl(xid_plus_direction[0]);
				xid_plus_direction[1] =
				    ntohl(xid_plus_direction[1]);
				/* Check message direction. */
				if (xid_plus_direction[1] == REPLY) {
					clnt_bck_svccall(xprt->xp_p2,
					    cd->mreq,
					    xid_plus_direction[0]);
					cd->mreq = NULL;
					continue;
				}
			}

			xdrmbuf_create(&xdrs, cd->mreq, XDR_DECODE);
			cd->mreq = NULL;

			/* Check for next request in a pending queue. */
			svc_vc_process_pending(xprt);
			if (cd->mreq == NULL || cd->resid != 0) {
				SOCKBUF_LOCK(&so->so_rcv);
				if (!soreadable(so))
					xprt_inactive_self(xprt);
				SOCKBUF_UNLOCK(&so->so_rcv);
			}

			sx_xunlock(&xprt->xp_lock);

			if (! xdr_callmsg(&xdrs, msg)) {
				XDR_DESTROY(&xdrs);
				return (FALSE);
			}

			*addrp = NULL;
			*mp = xdrmbuf_getall(&xdrs);
			XDR_DESTROY(&xdrs);

			return (TRUE);
		}

		/*
		 * The socket upcall calls xprt_active() which will eventually
		 * cause the server to call us here. We attempt to
		 * read as much as possible from the socket and put
		 * the result in cd->mpending. If the read fails,
		 * we have drained both cd->mpending and the socket so
		 * we can call xprt_inactive().
		 */
		uio.uio_resid = 1000000000;
		uio.uio_td = curthread;
		m = NULL;
		rcvflag = MSG_DONTWAIT;
		error = soreceive(so, NULL, &uio, &m, NULL, &rcvflag);

		if (error == EWOULDBLOCK) {
			/*
			 * We must re-test for readability after
			 * taking the lock to protect us in the case
			 * where a new packet arrives on the socket
			 * after our call to soreceive fails with
			 * EWOULDBLOCK.
			 */
			SOCKBUF_LOCK(&so->so_rcv);
			if (!soreadable(so))
				xprt_inactive_self(xprt);
			SOCKBUF_UNLOCK(&so->so_rcv);
			sx_xunlock(&xprt->xp_lock);
			return (FALSE);
		}

		if (error) {
			SOCKBUF_LOCK(&so->so_rcv);
			if (xprt->xp_upcallset) {
				xprt->xp_upcallset = 0;
				soupcall_clear(so, SO_RCV);
			}
			SOCKBUF_UNLOCK(&so->so_rcv);
			xprt_inactive_self(xprt);
			cd->strm_stat = XPRT_DIED;
			sx_xunlock(&xprt->xp_lock);
			return (FALSE);
		}

		if (!m) {
			/*
			 * EOF - the other end has closed the socket.
			 */
			xprt_inactive_self(xprt);
			cd->strm_stat = XPRT_DIED;
			sx_xunlock(&xprt->xp_lock);
			return (FALSE);
		}

		if (cd->mpending)
			m_last(cd->mpending)->m_next = m;
		else
			cd->mpending = m;
	}
}
Exemple #17
0
int
rpc_decode(u_char *buf, int len, struct rpc_msg *msg)
{
	XDR xdrs;
	u_int32_t fraghdr;
	u_char *p, *tmp;
	int stat, tmplen;

	if (len < 20)
		return (0);
	
	p = buf + 4;

	/* If not recognizably RPC, try TCP record defragmentation */
	if (pntohl(p) != CALL && pntohl(p) != REPLY) {
		tmp = buf;
		tmplen = 0;
		
		for (;;) {
			fraghdr = pntohl(tmp);
			
			if (FRAGLEN(fraghdr) + 4 > len)
				return (0);
			
			len -= 4;
			memmove(tmp, tmp + 4, len);
			tmplen += FRAGLEN(fraghdr);
			
			if (LASTFRAG(fraghdr))
				break;
			
			tmp += FRAGLEN(fraghdr);
			len -= FRAGLEN(fraghdr);
			
			if (len < 4)
				return (0);
		}
		len = tmplen;
	}
	/* Decode RPC message. */
	memset(msg, 0, sizeof(*msg));
	
	if (ntohl(((struct rpc_msg *)buf)->rm_direction) == CALL) {
		xdrmem_create(&xdrs, buf, len, XDR_DECODE);
		
		if (!xdr_callmsg(&xdrs, msg)) {
			xdr_destroy(&xdrs);
			return (0);
		}
	}
	else if (ntohl(((struct rpc_msg *)buf)->rm_direction) == REPLY) {
		msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void;
		xdrmem_create(&xdrs, buf, len, XDR_DECODE);
		
		if (!xdr_replymsg(&xdrs, msg)) {
			xdr_destroy(&xdrs);
			return (0);
		}
	}
	stat = xdr_getpos(&xdrs);
	xdr_destroy(&xdrs);
	
	return (stat);
}
Exemple #18
0
void
asrv::dispatch (ref<xhinfo> xi, const char *msg, ssize_t len,
                const sockaddr *src)
{
    if (!msg || len < 8 || getint (msg + 4) != CALL) {
        seteof (xi, src, len < 0);
        return;
    }

    xdrmem x (msg, len, XDR_DECODE);
    auto_ptr<svccb> sbp (New svccb);
    rpc_msg *m = &sbp->msg;

    if (!xdr_callmsg (x.xdrp (), m)) {
        trace (1) << "asrv::dispatch: xdr_callmsg failed\n";
        seteof (xi, src);
        return;
    }
    if (m->rm_call.cb_rpcvers != RPC_MSG_VERSION) {
        trace (1) << "asrv::dispatch: bad RPC message version\n";
        asrv_rpc_mismatch (xi, src, m->rm_xid);
        return;
    }

    asrv *s = xi->stab[progvers (sbp->prog (), sbp->vers ())];
    if (!s || !s->cb) {
        if (asrvtrace >= 1) {
            if (s)
                warn ("asrv::dispatch: no callback for %s (proc = %u)\n",
                      s->rpcprog->name, sbp->proc ());
            else
                warn ("asrv::dispatch: invalid prog/vers %u/%u (proc = %u)\n",
                      (u_int) sbp->prog (), (u_int) sbp->vers (),
                      (u_int) sbp->proc ());
        }
        asrv_accepterr (xi, src, PROG_UNAVAIL, m);
        return;
    }

    if (s->recv_hook)
        s->recv_hook ();

    sbp->init (s, src);

    if (sbp->proc () >= s->nproc) {
        if (asrvtrace >= 1)
            warn ("asrv::dispatch: invalid procno %s:%u\n",
                  s->rpcprog->name, (u_int) sbp->proc ());
        asrv_accepterr (xi, src, PROC_UNAVAIL, m);
        return;
    }

    if (s->isreplay (sbp.get ())) {
        trace (4, "replay %s:%s x=%x",
               s->rpcprog->name, s->tbl[m->rm_call.cb_proc].name,
               xidswap (m->rm_xid)) << sock2str (src) << "\n";
        return;
    }

    const rpcgen_table *rtp = &s->tbl[sbp->proc ()];
    sbp->arg = s->tbl[sbp->proc ()].alloc_arg ();
    if (!rtp->xdr_arg (x.xdrp (), sbp->arg)) {
        if (asrvtrace >= 1)
            warn ("asrv::dispatch: bad message %s:%s x=%x", s->rpcprog->name,
                  rtp->name, xidswap (m->rm_xid))
                    << sock2str (src) << "\n";
        asrv_accepterr (xi, src, GARBAGE_ARGS, m);
        s->inc_svccb_count ();
        s->sendreply (sbp.release (), NULL, true);
        return;
    }

    if (asrvtrace >= 2) {
        if (const authunix_parms *aup = sbp->getaup ())
            trace (2, "serve %s:%s x=%x u=%u g=%u",
                   s->rpcprog->name, rtp->name, xidswap (m->rm_xid),
                   aup->aup_uid, aup->aup_gid)
                    << sock2str (src) << "\n";
        else if (u_int32_t i = sbp->getaui ())
            trace (2, "serve %s:%s x=%x i=%u",
                   s->rpcprog->name, rtp->name, xidswap (m->rm_xid), i)
                    << sock2str (src) << "\n";
        else
            trace (2, "serve %s:%s x=%x",
                   s->rpcprog->name, rtp->name, xidswap (m->rm_xid))
                    << sock2str (src) << "\n";
    }
    if (asrvtrace >= 5 && rtp->print_arg)
        rtp->print_arg (sbp->arg, NULL, asrvtrace - 4, "ARGS", "");

    s->inc_svccb_count ();
    (*s->cb) (sbp.release ());
}
Exemple #19
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);
}
Exemple #20
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);
}
Exemple #21
0
/*
 * rpc_broadcast_exp()
 *
 * prog      - program number
 * vers      - version number
 * proc      - procedure number
 * xargs     - xdr routine for args
 * argsp     - pointer to args
 * xresults  - xdr routine for results
 * resultsp  - pointer to results
 * eachresult - call with each result obtained
 * inittime  - how long to wait initially
 * waittime  - maximum time to wait
 * nettype   - transport type
 */
enum clnt_stat
rpc_broadcast_exp(rpcprog_t prog, rpcvers_t vers, rpcproc_t proc,
    xdrproc_t xargs, caddr_t argsp, xdrproc_t xresults, caddr_t resultsp,
    resultproc_t eachresult, int inittime, int waittime,
    const char *nettype)
{
	enum clnt_stat	stat = RPC_SUCCESS; /* Return status */
	XDR 		xdr_stream; /* XDR stream */
	XDR 		*xdrs = &xdr_stream;
	struct rpc_msg	msg;	/* RPC message */
	struct timeval	t;
	char 		*outbuf = NULL;	/* Broadcast msg buffer */
	char		*inbuf = NULL; /* Reply buf */
	int		inlen;
	u_int 		maxbufsize = 0;
	AUTH 		*sys_auth = authunix_create_default();
	u_int		i;
	void		*handle;
	char		uaddress[1024];	/* A self imposed limit */
	char		*uaddrp = uaddress;
	int 		pmap_reply_flag; /* reply recvd from PORTMAP */
	/* An array of all the suitable broadcast transports */
	struct {
		int fd;		/* File descriptor */
		int af;
		int proto;
		struct netconfig *nconf; /* Netconfig structure */
		u_int asize;	/* Size of the addr buf */
		u_int dsize;	/* Size of the data buf */
		struct sockaddr_storage raddr; /* Remote address */
		broadlist_t nal;
	} fdlist[MAXBCAST];
	struct pollfd pfd[MAXBCAST];
	size_t fdlistno = 0;
	struct r_rpcb_rmtcallargs barg;	/* Remote arguments */
	struct r_rpcb_rmtcallres bres; /* Remote results */
	size_t outlen;
	struct netconfig *nconf;
	int msec;
	int pollretval;
	int fds_found;

#ifdef PORTMAP
	size_t outlen_pmap = 0;
	u_long port;		/* Remote port number */
	int pmap_flag = 0;	/* UDP exists ? */
	char *outbuf_pmap = NULL;
	struct rmtcallargs barg_pmap;	/* Remote arguments */
	struct rmtcallres bres_pmap; /* Remote results */
	u_int udpbufsz = 0;
#endif				/* PORTMAP */

	if (sys_auth == NULL) {
		return (RPC_SYSTEMERROR);
	}
	/*
	 * initialization: create a fd, a broadcast address, and send the
	 * request on the broadcast transport.
	 * Listen on all of them and on replies, call the user supplied
	 * function.
	 */

	if (nettype == NULL)
		nettype = "datagram_n";
	if ((handle = __rpc_setconf(nettype)) == NULL) {
		AUTH_DESTROY(sys_auth);
		return (RPC_UNKNOWNPROTO);
	}
	while ((nconf = __rpc_getconf(handle)) != NULL) {
		int fd;
		struct __rpc_sockinfo si;

		if (nconf->nc_semantics != NC_TPI_CLTS)
			continue;
		if (fdlistno >= MAXBCAST)
			break;	/* No more slots available */
		if (!__rpc_nconf2sockinfo(nconf, &si))
			continue;

		TAILQ_INIT(&fdlist[fdlistno].nal);
		if (__rpc_getbroadifs(si.si_af, si.si_proto, si.si_socktype, 
		    &fdlist[fdlistno].nal) == 0)
			continue;

		fd = _socket(si.si_af, si.si_socktype, si.si_proto);
		if (fd < 0) {
			stat = RPC_CANTSEND;
			continue;
		}
		fdlist[fdlistno].af = si.si_af;
		fdlist[fdlistno].proto = si.si_proto;
		fdlist[fdlistno].fd = fd;
		fdlist[fdlistno].nconf = nconf;
		fdlist[fdlistno].asize = __rpc_get_a_size(si.si_af);
		pfd[fdlistno].events = POLLIN | POLLPRI |
			POLLRDNORM | POLLRDBAND;
		pfd[fdlistno].fd = fdlist[fdlistno].fd = fd;
		fdlist[fdlistno].dsize = __rpc_get_t_size(si.si_af, si.si_proto,
							  0);

		if (maxbufsize <= fdlist[fdlistno].dsize)
			maxbufsize = fdlist[fdlistno].dsize;

#ifdef PORTMAP
		if (si.si_af == AF_INET && si.si_proto == IPPROTO_UDP) {
			udpbufsz = fdlist[fdlistno].dsize;
			if ((outbuf_pmap = malloc(udpbufsz)) == NULL) {
				_close(fd);
				stat = RPC_SYSTEMERROR;
				goto done_broad;
			}
			pmap_flag = 1;
		}
#endif				/* PORTMAP */
		fdlistno++;
	}

	if (fdlistno == 0) {
		if (stat == RPC_SUCCESS)
			stat = RPC_UNKNOWNPROTO;
		goto done_broad;
	}
	if (maxbufsize == 0) {
		if (stat == RPC_SUCCESS)
			stat = RPC_CANTSEND;
		goto done_broad;
	}
	inbuf = malloc(maxbufsize);
	outbuf = malloc(maxbufsize);
	if ((inbuf == NULL) || (outbuf == NULL)) {
		stat = RPC_SYSTEMERROR;
		goto done_broad;
	}

	/* Serialize all the arguments which have to be sent */
	(void) gettimeofday(&t, NULL);
	msg.rm_xid = __RPC_GETXID(&t);
	msg.rm_direction = CALL;
	msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
	msg.rm_call.cb_prog = RPCBPROG;
	msg.rm_call.cb_vers = RPCBVERS;
	msg.rm_call.cb_proc = RPCBPROC_CALLIT;
	barg.prog = prog;
	barg.vers = vers;
	barg.proc = proc;
	barg.args.args_val = argsp;
	barg.xdr_args = xargs;
	bres.addr = uaddrp;
	bres.results.results_val = resultsp;
	bres.xdr_res = xresults;
	msg.rm_call.cb_cred = sys_auth->ah_cred;
	msg.rm_call.cb_verf = sys_auth->ah_verf;
	xdrmem_create(xdrs, outbuf, maxbufsize, XDR_ENCODE);
	if ((!xdr_callmsg(xdrs, &msg)) ||
	    (!xdr_rpcb_rmtcallargs(xdrs,
	    (struct rpcb_rmtcallargs *)(void *)&barg))) {
		stat = RPC_CANTENCODEARGS;
		goto done_broad;
	}
	outlen = xdr_getpos(xdrs);
	xdr_destroy(xdrs);

#ifdef PORTMAP
	/* Prepare the packet for version 2 PORTMAP */
	if (pmap_flag) {
		msg.rm_xid++;	/* One way to distinguish */
		msg.rm_call.cb_prog = PMAPPROG;
		msg.rm_call.cb_vers = PMAPVERS;
		msg.rm_call.cb_proc = PMAPPROC_CALLIT;
		barg_pmap.prog = prog;
		barg_pmap.vers = vers;
		barg_pmap.proc = proc;
		barg_pmap.args_ptr = argsp;
		barg_pmap.xdr_args = xargs;
		bres_pmap.port_ptr = &port;
		bres_pmap.xdr_results = xresults;
		bres_pmap.results_ptr = resultsp;
		xdrmem_create(xdrs, outbuf_pmap, udpbufsz, XDR_ENCODE);
		if ((! xdr_callmsg(xdrs, &msg)) ||
		    (! xdr_rmtcall_args(xdrs, &barg_pmap))) {
			stat = RPC_CANTENCODEARGS;
			goto done_broad;
		}
		outlen_pmap = xdr_getpos(xdrs);
		xdr_destroy(xdrs);
	}
#endif				/* PORTMAP */

	/*
	 * Basic loop: broadcast the packets to transports which
	 * support data packets of size such that one can encode
	 * all the arguments.
	 * Wait a while for response(s).
	 * The response timeout grows larger per iteration.
	 */
	for (msec = inittime; msec <= waittime; msec += msec) {
		struct broadif *bip;

		/* Broadcast all the packets now */
		for (i = 0; i < fdlistno; i++) {
			if (fdlist[i].dsize < outlen) {
				stat = RPC_CANTSEND;
				continue;
			}
			for (bip = TAILQ_FIRST(&fdlist[i].nal); bip != NULL;
			     bip = TAILQ_NEXT(bip, link)) {
				void *addr;

				addr = &bip->broadaddr;

				__rpc_broadenable(fdlist[i].af, fdlist[i].fd,
				    bip);

				/*
				 * Only use version 3 if lowvers is not set
				 */

				if (!__rpc_lowvers)
					if (_sendto(fdlist[i].fd, outbuf,
					    outlen, 0, (struct sockaddr*)addr,
					    (size_t)fdlist[i].asize) !=
					    outlen) {
#ifdef RPC_DEBUG
						perror("sendto");
#endif
						warnx("clnt_bcast: cannot send "
						      "broadcast packet");
						stat = RPC_CANTSEND;
						continue;
					}
#ifdef RPC_DEBUG
				if (!__rpc_lowvers)
					fprintf(stderr, "Broadcast packet sent "
						"for %s\n",
						 fdlist[i].nconf->nc_netid);
#endif
#ifdef PORTMAP
				/*
				 * Send the version 2 packet also
				 * for UDP/IP
				 */
				if (pmap_flag &&
				    fdlist[i].proto == IPPROTO_UDP) {
					if (_sendto(fdlist[i].fd, outbuf_pmap,
					    outlen_pmap, 0, addr,
					    (size_t)fdlist[i].asize) !=
						outlen_pmap) {
						warnx("clnt_bcast: "
						    "Cannot send broadcast packet");
						stat = RPC_CANTSEND;
						continue;
					}
				}
#ifdef RPC_DEBUG
				fprintf(stderr, "PMAP Broadcast packet "
					"sent for %s\n",
					fdlist[i].nconf->nc_netid);
#endif
#endif				/* PORTMAP */
			}
			/* End for sending all packets on this transport */
		}	/* End for sending on all transports */

		if (eachresult == NULL) {
			stat = RPC_SUCCESS;
			goto done_broad;
		}

		/*
		 * Get all the replies from these broadcast requests
		 */
	recv_again:

		switch (pollretval = _poll(pfd, fdlistno, msec)) {
		case 0:		/* timed out */
			stat = RPC_TIMEDOUT;
			continue;
		case -1:	/* some kind of error - we ignore it */
			goto recv_again;
		}		/* end of poll results switch */

		for (i = fds_found = 0;
		     i < fdlistno && fds_found < pollretval; i++) {
			bool_t done = FALSE;

			if (pfd[i].revents == 0)
				continue;
			else if (pfd[i].revents & POLLNVAL) {
				/*
				 * Something bad has happened to this descri-
				 * ptor. We can cause _poll() to ignore
				 * it simply by using a negative fd.  We do that
				 * rather than compacting the pfd[] and fdlist[]
				 * arrays.
				 */
				pfd[i].fd = -1;
				fds_found++;
				continue;
			} else
				fds_found++;
#ifdef RPC_DEBUG
			fprintf(stderr, "response for %s\n",
				fdlist[i].nconf->nc_netid);
#endif
		try_again:
			inlen = _recvfrom(fdlist[i].fd, inbuf, fdlist[i].dsize,
			    0, (struct sockaddr *)(void *)&fdlist[i].raddr,
			    &fdlist[i].asize);
			if (inlen < 0) {
				if (errno == EINTR)
					goto try_again;
				warnx("clnt_bcast: Cannot receive reply to "
					"broadcast");
				stat = RPC_CANTRECV;
				continue;
			}
			if (inlen < sizeof (u_int32_t))
				continue; /* Drop that and go ahead */
			/*
			 * see if reply transaction id matches sent id.
			 * If so, decode the results. If return id is xid + 1
			 * it was a PORTMAP reply
			 */
			if (*((u_int32_t *)(void *)(inbuf)) ==
			    *((u_int32_t *)(void *)(outbuf))) {
				pmap_reply_flag = 0;
				msg.acpted_rply.ar_verf = _null_auth;
				msg.acpted_rply.ar_results.where =
					(caddr_t)(void *)&bres;
				msg.acpted_rply.ar_results.proc =
					(xdrproc_t)xdr_rpcb_rmtcallres;
#ifdef PORTMAP
			} else if (pmap_flag &&
				*((u_int32_t *)(void *)(inbuf)) ==
				*((u_int32_t *)(void *)(outbuf_pmap))) {
				pmap_reply_flag = 1;
				msg.acpted_rply.ar_verf = _null_auth;
				msg.acpted_rply.ar_results.where =
					(caddr_t)(void *)&bres_pmap;
				msg.acpted_rply.ar_results.proc =
					(xdrproc_t)xdr_rmtcallres;
#endif				/* PORTMAP */
			} else
				continue;
			xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE);
			if (xdr_replymsg(xdrs, &msg)) {
				if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
				    (msg.acpted_rply.ar_stat == SUCCESS)) {
					struct netbuf taddr, *np;
					struct sockaddr_in *sin;

#ifdef PORTMAP
					if (pmap_flag && pmap_reply_flag) {
						sin = (struct sockaddr_in *)
						    (void *)&fdlist[i].raddr;
						sin->sin_port =
						    htons((u_short)port);
						taddr.len = taddr.maxlen = 
						    fdlist[i].raddr.ss_len;
						taddr.buf = &fdlist[i].raddr;
						done = (*eachresult)(resultsp,
						    &taddr, fdlist[i].nconf);
					} else {
#endif				/* PORTMAP */
#ifdef RPC_DEBUG
						fprintf(stderr, "uaddr %s\n",
						    uaddrp);
#endif
						np = uaddr2taddr(
						    fdlist[i].nconf, uaddrp);
						done = (*eachresult)(resultsp,
						    np, fdlist[i].nconf);
						free(np);
#ifdef PORTMAP
					}
#endif				/* PORTMAP */
				}
				/* otherwise, we just ignore the errors ... */
			}
			/* else some kind of deserialization problem ... */

			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;
			}
		}		/* The recv for loop */
	}			/* The giant for loop */

done_broad:
	free(inbuf);
	free(outbuf);
#ifdef PORTMAP
	free(outbuf_pmap);
#endif				/* PORTMAP */
	for (i = 0; i < fdlistno; i++) {
		(void)_close(fdlist[i].fd);
		__rpc_freebroadifs(&fdlist[i].nal);
	}
	AUTH_DESTROY(sys_auth);
	(void) __rpc_endconf(handle);

	return (stat);
}
Exemple #22
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);
}
Exemple #23
0
static bool_t
svc_dg_recv(SVCXPRT *xprt, struct rpc_msg *msg,
    struct sockaddr **addrp, struct mbuf **mp)
{
	struct uio uio;
	struct sockaddr *raddr;
	struct mbuf *mreq;
	XDR xdrs;
	int error, rcvflag;

	/*
	 * Serialise access to the socket.
	 */
	sx_xlock(&xprt->xp_lock);

	/*
	 * The socket upcall calls xprt_active() which will eventually
	 * cause the server to call us here. We attempt to read a
	 * packet from the socket and process it. If the read fails,
	 * we have drained all pending requests so we call
	 * xprt_inactive().
	 */
	uio.uio_resid = 1000000000;
	uio.uio_td = curthread;
	mreq = NULL;
	rcvflag = MSG_DONTWAIT;
	error = soreceive(xprt->xp_socket, &raddr, &uio, &mreq, NULL, &rcvflag);

	if (error == EWOULDBLOCK) {
		/*
		 * We must re-test for readability after taking the
		 * lock to protect us in the case where a new packet
		 * arrives on the socket after our call to soreceive
		 * fails with EWOULDBLOCK. The pool lock protects us
		 * from racing the upcall after our soreadable() call
		 * returns false.
		 */
		mtx_lock(&xprt->xp_pool->sp_lock);
		if (!soreadable(xprt->xp_socket))
			xprt_inactive_locked(xprt);
		mtx_unlock(&xprt->xp_pool->sp_lock);
		sx_xunlock(&xprt->xp_lock);
		return (FALSE);
	}

	if (error) {
		SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
		soupcall_clear(xprt->xp_socket, SO_RCV);
		SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
		xprt_inactive(xprt);
		sx_xunlock(&xprt->xp_lock);
		return (FALSE);
	}

	sx_xunlock(&xprt->xp_lock);

	xdrmbuf_create(&xdrs, mreq, XDR_DECODE);
	if (! xdr_callmsg(&xdrs, msg)) {
		XDR_DESTROY(&xdrs);
		return (FALSE);
	}

	*addrp = raddr;
	*mp = xdrmbuf_getall(&xdrs);
	XDR_DESTROY(&xdrs);

	return (TRUE);
}
Exemple #24
0
static bool_t
svc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg,
    struct sockaddr **addrp, struct mbuf **mp)
{
	struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1;
	struct uio uio;
	struct mbuf *m;
	XDR xdrs;
	int error, rcvflag;

	/*
	 * Serialise access to the socket and our own record parsing
	 * state.
	 */
	sx_xlock(&xprt->xp_lock);

	for (;;) {
		/*
		 * If we have an mbuf chain in cd->mpending, try to parse a
		 * record from it, leaving the result in cd->mreq. If we don't
		 * have a complete record, leave the partial result in
		 * cd->mreq and try to read more from the socket.
		 */
		if (cd->mpending) {
			/*
			 * If cd->resid is non-zero, we have part of the
			 * record already, otherwise we are expecting a record
			 * marker.
			 */
			if (!cd->resid) {
				/*
				 * See if there is enough data buffered to
				 * make up a record marker. Make sure we can
				 * handle the case where the record marker is
				 * split across more than one mbuf.
				 */
				size_t n = 0;
				uint32_t header;

				m = cd->mpending;
				while (n < sizeof(uint32_t) && m) {
					n += m->m_len;
					m = m->m_next;
				}
				if (n < sizeof(uint32_t))
					goto readmore;
				if (cd->mpending->m_len < sizeof(uint32_t))
					cd->mpending = m_pullup(cd->mpending,
					    sizeof(uint32_t));
				memcpy(&header, mtod(cd->mpending, uint32_t *),
				    sizeof(header));
				header = ntohl(header);
				cd->eor = (header & 0x80000000) != 0;
				cd->resid = header & 0x7fffffff;
				m_adj(cd->mpending, sizeof(uint32_t));
			}

			/*
			 * Start pulling off mbufs from cd->mpending
			 * until we either have a complete record or
			 * we run out of data. We use m_split to pull
			 * data - it will pull as much as possible and
			 * split the last mbuf if necessary.
			 */
			while (cd->mpending && cd->resid) {
				m = cd->mpending;
				if (cd->mpending->m_next
				    || cd->mpending->m_len > cd->resid)
					cd->mpending = m_split(cd->mpending,
					    cd->resid, M_WAIT);
				else
					cd->mpending = NULL;
				if (cd->mreq)
					m_last(cd->mreq)->m_next = m;
				else
					cd->mreq = m;
				while (m) {
					cd->resid -= m->m_len;
					m = m->m_next;
				}
			}

			/*
			 * If cd->resid is zero now, we have managed to
			 * receive a record fragment from the stream. Check
			 * for the end-of-record mark to see if we need more.
			 */
			if (cd->resid == 0) {
				if (!cd->eor)
					continue;

				/*
				 * Success - we have a complete record in
				 * cd->mreq.
				 */
				xdrmbuf_create(&xdrs, cd->mreq, XDR_DECODE);
				cd->mreq = NULL;
				sx_xunlock(&xprt->xp_lock);

				if (! xdr_callmsg(&xdrs, msg)) {
					XDR_DESTROY(&xdrs);
					return (FALSE);
				}

				*addrp = NULL;
				*mp = xdrmbuf_getall(&xdrs);
				XDR_DESTROY(&xdrs);

				return (TRUE);
			}
		}

	readmore:
		/*
		 * The socket upcall calls xprt_active() which will eventually
		 * cause the server to call us here. We attempt to
		 * read as much as possible from the socket and put
		 * the result in cd->mpending. If the read fails,
		 * we have drained both cd->mpending and the socket so
		 * we can call xprt_inactive().
		 */
		uio.uio_resid = 1000000000;
		uio.uio_td = curthread;
		m = NULL;
		rcvflag = MSG_DONTWAIT;
		CURVNET_SET(xprt->xp_socket->so_vnet);
		error = soreceive(xprt->xp_socket, NULL, &uio, &m, NULL,
		    &rcvflag);
		CURVNET_RESTORE();

		if (error == EWOULDBLOCK) {
			/*
			 * We must re-test for readability after
			 * taking the lock to protect us in the case
			 * where a new packet arrives on the socket
			 * after our call to soreceive fails with
			 * EWOULDBLOCK. The pool lock protects us from
			 * racing the upcall after our soreadable()
			 * call returns false.
			 */
			mtx_lock(&xprt->xp_pool->sp_lock);
			if (!soreadable(xprt->xp_socket))
				xprt_inactive_locked(xprt);
			mtx_unlock(&xprt->xp_pool->sp_lock);
			sx_xunlock(&xprt->xp_lock);
			return (FALSE);
		}

		if (error) {
			SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
			if (xprt->xp_upcallset) {
				xprt->xp_upcallset = 0;
				soupcall_clear(xprt->xp_socket, SO_RCV);
			}
			SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
			xprt_inactive(xprt);
			cd->strm_stat = XPRT_DIED;
			sx_xunlock(&xprt->xp_lock);
			return (FALSE);
		}

		if (!m) {
			/*
			 * EOF - the other end has closed the socket.
			 */
			xprt_inactive(xprt);
			cd->strm_stat = XPRT_DIED;
			sx_xunlock(&xprt->xp_lock);
			return (FALSE);
		}

		if (cd->mpending)
			m_last(cd->mpending)->m_next = m;
		else
			cd->mpending = m;
	}
Exemple #25
0
/*
 * Receive rpc requests.
 * Pulls a request in off the socket, checks if the packet is intact,
 * and deserializes the call packet.
 */
static bool_t
svc_clts_krecv(SVCXPRT *clone_xprt, mblk_t *mp, struct rpc_msg *msg)
{
	/* LINTED pointer alignment */
	struct udp_data *ud = (struct udp_data *)clone_xprt->xp_p2buf;
	XDR *xdrs = &clone_xprt->xp_xdrin;
	struct rpc_clts_server *stats = CLONE2STATS(clone_xprt);
	union T_primitives *pptr;
	int hdrsz;

	TRACE_0(TR_FAC_KRPC, TR_SVC_CLTS_KRECV_START,
	    "svc_clts_krecv_start:");

	RSSTAT_INCR(stats, rscalls);

	/*
	 * The incoming request should start with an M_PROTO message.
	 */
	if (mp->b_datap->db_type != M_PROTO) {
		goto bad;
	}

	/*
	 * The incoming request should be an T_UNITDTA_IND.  There
	 * might be other messages coming up the stream, but we can
	 * ignore them.
	 */
	pptr = (union T_primitives *)mp->b_rptr;
	if (pptr->type != T_UNITDATA_IND) {
		goto bad;
	}
	/*
	 * Do some checking to make sure that the header at least looks okay.
	 */
	hdrsz = (int)(mp->b_wptr - mp->b_rptr);
	if (hdrsz < TUNITDATAINDSZ ||
	    hdrsz < (pptr->unitdata_ind.OPT_offset +
		    pptr->unitdata_ind.OPT_length) ||
	    hdrsz < (pptr->unitdata_ind.SRC_offset +
		    pptr->unitdata_ind.SRC_length)) {
		goto bad;
	}

	/*
	 * Make sure that the transport provided a usable address.
	 */
	if (pptr->unitdata_ind.SRC_length <= 0) {
		goto bad;
	}
	/*
	 * Point the remote transport address in the service_transport
	 * handle at the address in the request.
	 */
	clone_xprt->xp_rtaddr.buf = (char *)mp->b_rptr +
	    pptr->unitdata_ind.SRC_offset;
	clone_xprt->xp_rtaddr.len = pptr->unitdata_ind.SRC_length;

	/*
	 * Save the first mblk which contains the T_unidata_ind in
	 * ud_resp.  It will be used to generate the T_unitdata_req
	 * during the reply.
	 */
	if (ud->ud_resp) {
		if (ud->ud_resp->b_cont != NULL) {
			cmn_err(CE_WARN, "svc_clts_krecv: ud_resp %p, "
			    "b_cont %p", (void *)ud->ud_resp,
			    (void *)ud->ud_resp->b_cont);
		}
		freeb(ud->ud_resp);
	}
	ud->ud_resp = mp;
	mp = mp->b_cont;
	ud->ud_resp->b_cont = NULL;

	xdrmblk_init(xdrs, mp, XDR_DECODE, 0);

	TRACE_0(TR_FAC_KRPC, TR_XDR_CALLMSG_START,
	    "xdr_callmsg_start:");
	if (! xdr_callmsg(xdrs, msg)) {
		TRACE_1(TR_FAC_KRPC, TR_XDR_CALLMSG_END,
		    "xdr_callmsg_end:(%S)", "bad");
		RSSTAT_INCR(stats, rsxdrcall);
		goto bad;
	}
	TRACE_1(TR_FAC_KRPC, TR_XDR_CALLMSG_END,
	    "xdr_callmsg_end:(%S)", "good");

	clone_xprt->xp_xid = msg->rm_xid;
	ud->ud_inmp = mp;

	TRACE_1(TR_FAC_KRPC, TR_SVC_CLTS_KRECV_END,
	    "svc_clts_krecv_end:(%S)", "good");
	return (TRUE);

bad:
	if (mp)
		freemsg(mp);
	if (ud->ud_resp) {
		/*
		 * There should not be any left over results buffer.
		 */
		ASSERT(ud->ud_resp->b_cont == NULL);
		freeb(ud->ud_resp);
		ud->ud_resp = NULL;
	}

	RSSTAT_INCR(stats, rsbadcalls);
	TRACE_1(TR_FAC_KRPC, TR_SVC_CLTS_KRECV_END,
	    "svc_clts_krecv_end:(%S)", "bad");
	return (FALSE);
}