#include "mt.h"
#include "rpc_mt.h"
#include <stdlib.h>
#include <rpc/rpc.h>
#include <syslog.h>
extern mutex_t clntraw_lock;
#define MCALL_MSG_SIZE 24
static struct clnt_raw_private {
CLIENT client_object;
struct netbuf *raw_netbuf;
char mashl_callmsg[MCALL_MSG_SIZE];
uint_t mcnt;
} *clnt_raw_private;
static struct clnt_ops *clnt_raw_ops();
extern bool_t xdr_opaque_auth();
extern struct netbuf _rawcomnetbuf;
CLIENT *
clnt_raw_create(const rpcprog_t prog, const rpcvers_t vers)
{
struct clnt_raw_private *clp;
struct rpc_msg call_msg;
XDR xdrs;
CLIENT *client;
uint_t start;
(void) mutex_lock(&clntraw_lock);
clp = clnt_raw_private;
if (clp != NULL) {
(void) mutex_unlock(&clntraw_lock);
return (&clp->client_object);
}
clp = calloc(1, sizeof (*clp));
if (clp == NULL) {
(void) mutex_unlock(&clntraw_lock);
return (NULL);
}
clp->raw_netbuf = &_rawcomnetbuf;
call_msg.rm_direction = CALL;
call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
call_msg.rm_call.cb_prog = prog;
call_msg.rm_call.cb_vers = vers;
xdrmem_create(&xdrs, clp->mashl_callmsg, sizeof (clp->mashl_callmsg),
XDR_ENCODE);
start = XDR_GETPOS(&xdrs);
if (!xdr_callhdr(&xdrs, &call_msg)) {
free(clp);
(void) syslog(LOG_ERR,
"clnt_raw_create: Fatal header serialization error");
(void) mutex_unlock(&clntraw_lock);
return (NULL);
}
clp->mcnt = XDR_GETPOS(&xdrs) - start;
XDR_DESTROY(&xdrs);
client = &clp->client_object;
client->cl_ops = clnt_raw_ops();
client->cl_auth = authnone_create();
clnt_raw_private = clp;
(void) mutex_unlock(&clntraw_lock);
return (client);
}
static enum clnt_stat
clnt_raw_call(CLIENT *h, rpcproc_t proc, xdrproc_t xargs, caddr_t argsp,
xdrproc_t xresults, caddr_t resultsp, struct timeval timeout)
{
struct clnt_raw_private *clp;
XDR xdrs;
struct rpc_msg msg;
uint_t start;
rpc_callerr.re_errno = 0;
rpc_callerr.re_terrno = 0;
(void) mutex_lock(&clntraw_lock);
clp = clnt_raw_private;
if (clp == NULL) {
(void) mutex_unlock(&clntraw_lock);
return (rpc_callerr.re_status = RPC_FAILED);
}
(void) mutex_unlock(&clntraw_lock);
call_again:
xdrmem_create(&xdrs, clp->raw_netbuf->buf, clp->raw_netbuf->maxlen,
XDR_ENCODE);
start = XDR_GETPOS(&xdrs);
((struct rpc_msg *)clp->mashl_callmsg)->rm_xid++;
if ((!XDR_PUTBYTES(&xdrs, clp->mashl_callmsg, clp->mcnt)) ||
(!XDR_PUTINT32(&xdrs, (int32_t *)&proc)) ||
(!AUTH_MARSHALL(h->cl_auth, &xdrs)) ||
(!(*xargs)(&xdrs, argsp))) {
XDR_DESTROY(&xdrs);
return (rpc_callerr.re_status = RPC_CANTENCODEARGS);
}
clp->raw_netbuf->len = XDR_GETPOS(&xdrs) - start;
XDR_DESTROY(&xdrs);
svc_getreq_common(FD_SETSIZE);
xdrmem_create(&xdrs, clp->raw_netbuf->buf, clp->raw_netbuf->len,
XDR_DECODE);
msg.acpted_rply.ar_verf = _null_auth;
msg.acpted_rply.ar_results.where = resultsp;
msg.acpted_rply.ar_results.proc = xresults;
if (!xdr_replymsg(&xdrs, &msg)) {
XDR_DESTROY(&xdrs);
return (rpc_callerr.re_status = RPC_CANTDECODERES);
}
XDR_DESTROY(&xdrs);
if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
(msg.acpted_rply.ar_stat == SUCCESS))
rpc_callerr.re_status = RPC_SUCCESS;
else
__seterr_reply(&msg, &rpc_callerr);
if (rpc_callerr.re_status == RPC_SUCCESS) {
if (!AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) {
rpc_callerr.re_status = RPC_AUTHERROR;
rpc_callerr.re_why = AUTH_INVALIDRESP;
}
if (msg.acpted_rply.ar_verf.oa_base != NULL) {
xdr_free(xdr_opaque_auth,
(char *)&(msg.acpted_rply.ar_verf));
}
} else {
if (AUTH_REFRESH(h->cl_auth, &msg))
goto call_again;
}
return (rpc_callerr.re_status);
}
static enum clnt_stat
clnt_raw_send(CLIENT *h, rpcproc_t proc, xdrproc_t xargs, caddr_t argsp)
{
struct clnt_raw_private *clp;
XDR xdrs;
uint_t start;
rpc_callerr.re_errno = 0;
rpc_callerr.re_terrno = 0;
(void) mutex_lock(&clntraw_lock);
clp = clnt_raw_private;
if (clp == NULL) {
(void) mutex_unlock(&clntraw_lock);
return (rpc_callerr.re_status = RPC_FAILED);
}
(void) mutex_unlock(&clntraw_lock);
xdrmem_create(&xdrs, clp->raw_netbuf->buf, clp->raw_netbuf->maxlen,
XDR_ENCODE);
start = XDR_GETPOS(&xdrs);
((struct rpc_msg *)clp->mashl_callmsg)->rm_xid++;
if ((!XDR_PUTBYTES(&xdrs, clp->mashl_callmsg, clp->mcnt)) ||
(!XDR_PUTINT32(&xdrs, (int32_t *)&proc)) ||
(!AUTH_MARSHALL(h->cl_auth, &xdrs)) ||
(!(*xargs)(&xdrs, argsp))) {
XDR_DESTROY(&xdrs);
return (rpc_callerr.re_status = RPC_CANTENCODEARGS);
}
clp->raw_netbuf->len = XDR_GETPOS(&xdrs) - start;
XDR_DESTROY(&xdrs);
svc_getreq_common(FD_SETSIZE);
return (rpc_callerr.re_status = RPC_SUCCESS);
}
static void
clnt_raw_geterr(CLIENT *cl, struct rpc_err *errp)
{
*errp = rpc_callerr;
}
static bool_t
clnt_raw_freeres(CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr)
{
struct clnt_raw_private *clp;
(void) mutex_lock(&clntraw_lock);
clp = clnt_raw_private;
if (clp == NULL) {
(void) mutex_unlock(&clntraw_lock);
return (FALSE);
}
(void) mutex_unlock(&clntraw_lock);
xdr_free(xdr_res, res_ptr);
return (TRUE);
}
static void
clnt_raw_abort(CLIENT *cl, struct rpc_err *errp)
{
}
static bool_t
clnt_raw_control(CLIENT *cl, int request, char *info)
{
return (FALSE);
}
static void
clnt_raw_destroy(CLIENT *cl)
{
}
static struct clnt_ops *
clnt_raw_ops(void)
{
static struct clnt_ops ops;
extern mutex_t ops_lock;
(void) mutex_lock(&ops_lock);
if (ops.cl_call == NULL) {
ops.cl_call = clnt_raw_call;
ops.cl_send = clnt_raw_send;
ops.cl_abort = clnt_raw_abort;
ops.cl_geterr = clnt_raw_geterr;
ops.cl_freeres = clnt_raw_freeres;
ops.cl_destroy = clnt_raw_destroy;
ops.cl_control = clnt_raw_control;
}
(void) mutex_unlock(&ops_lock);
return (&ops);
}