summaryrefslogtreecommitdiffstats
path: root/sys/rpc/svc_vc.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/rpc/svc_vc.c')
-rw-r--r--sys/rpc/svc_vc.c176
1 files changed, 170 insertions, 6 deletions
diff --git a/sys/rpc/svc_vc.c b/sys/rpc/svc_vc.c
index ca8239b..667d84c 100644
--- a/sys/rpc/svc_vc.c
+++ b/sys/rpc/svc_vc.c
@@ -65,6 +65,7 @@ __FBSDID("$FreeBSD$");
#include <rpc/rpc.h>
+#include <rpc/krpc.h>
#include <rpc/rpc_com.h>
#include <security/mac/mac_framework.h>
@@ -83,6 +84,14 @@ static bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *,
static bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in);
static bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq,
void *in);
+static void svc_vc_backchannel_destroy(SVCXPRT *);
+static enum xprt_stat svc_vc_backchannel_stat(SVCXPRT *);
+static bool_t svc_vc_backchannel_recv(SVCXPRT *, struct rpc_msg *,
+ struct sockaddr **, struct mbuf **);
+static bool_t svc_vc_backchannel_reply(SVCXPRT *, struct rpc_msg *,
+ struct sockaddr *, struct mbuf *);
+static bool_t svc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq,
+ void *in);
static SVCXPRT *svc_vc_create_conn(SVCPOOL *pool, struct socket *so,
struct sockaddr *raddr);
static int svc_vc_accept(struct socket *head, struct socket **sop);
@@ -105,12 +114,12 @@ static struct xp_ops svc_vc_ops = {
.xp_control = svc_vc_control
};
-struct cf_conn { /* kept in xprt->xp_p1 for actual connection */
- enum xprt_stat strm_stat;
- struct mbuf *mpending; /* unparsed data read from the socket */
- struct mbuf *mreq; /* current record being built from mpending */
- uint32_t resid; /* number of bytes needed for fragment */
- bool_t eor; /* reading last fragment of current record */
+static struct xp_ops svc_vc_backchannel_ops = {
+ .xp_recv = svc_vc_backchannel_recv,
+ .xp_stat = svc_vc_backchannel_stat,
+ .xp_reply = svc_vc_backchannel_reply,
+ .xp_destroy = svc_vc_backchannel_destroy,
+ .xp_control = svc_vc_backchannel_control
};
/*
@@ -267,6 +276,28 @@ cleanup_svc_vc_create:
}
/*
+ * Create a new transport for a backchannel on a clnt_vc socket.
+ */
+SVCXPRT *
+svc_vc_create_backchannel(SVCPOOL *pool)
+{
+ SVCXPRT *xprt = NULL;
+ struct cf_conn *cd = NULL;
+
+ cd = mem_alloc(sizeof(*cd));
+ cd->strm_stat = XPRT_IDLE;
+
+ xprt = svc_xprt_alloc();
+ sx_init(&xprt->xp_lock, "xprt->xp_lock");
+ xprt->xp_pool = pool;
+ xprt->xp_socket = NULL;
+ xprt->xp_p1 = cd;
+ xprt->xp_p2 = NULL;
+ xprt->xp_ops = &svc_vc_backchannel_ops;
+ return (xprt);
+}
+
+/*
* This does all of the accept except the final call to soaccept. The
* caller will call soaccept after dropping its locks (soaccept may
* call malloc).
@@ -452,6 +483,22 @@ svc_vc_destroy(SVCXPRT *xprt)
mem_free(cd, sizeof(*cd));
}
+static void
+svc_vc_backchannel_destroy(SVCXPRT *xprt)
+{
+ struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1;
+ struct mbuf *m, *m2;
+
+ svc_xprt_free(xprt);
+ m = cd->mreq;
+ while (m != NULL) {
+ m2 = m;
+ m = m->m_nextpkt;
+ m_freem(m2);
+ }
+ mem_free(cd, sizeof(*cd));
+}
+
/*ARGSUSED*/
static bool_t
svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in)
@@ -466,6 +513,13 @@ svc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in)
return (FALSE);
}
+static bool_t
+svc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq, void *in)
+{
+
+ return (FALSE);
+}
+
static enum xprt_stat
svc_vc_stat(SVCXPRT *xprt)
{
@@ -506,6 +560,19 @@ svc_vc_stat(SVCXPRT *xprt)
return (XPRT_IDLE);
}
+static enum xprt_stat
+svc_vc_backchannel_stat(SVCXPRT *xprt)
+{
+ struct cf_conn *cd;
+
+ cd = (struct cf_conn *)(xprt->xp_p1);
+
+ if (cd->mreq != NULL)
+ return (XPRT_MOREREQS);
+
+ return (XPRT_IDLE);
+}
+
static bool_t
svc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg,
struct sockaddr **addrp, struct mbuf **mp)
@@ -680,6 +747,44 @@ svc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg,
}
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(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);
+}
+
+static bool_t
svc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg,
struct sockaddr *addr, struct mbuf *m)
{
@@ -733,6 +838,65 @@ svc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg,
}
static bool_t
+svc_vc_backchannel_reply(SVCXPRT *xprt, struct rpc_msg *msg,
+ struct sockaddr *addr, struct mbuf *m)
+{
+ struct ct_data *ct;
+ XDR xdrs;
+ struct mbuf *mrep;
+ bool_t stat = TRUE;
+ int error;
+
+ /*
+ * Leave space for record mark.
+ */
+ MGETHDR(mrep, M_WAITOK, MT_DATA);
+ mrep->m_len = 0;
+ 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);
+}
+
+static bool_t
svc_vc_null()
{
OpenPOWER on IntegriCloud