#include "mt.h"
#include "rpc_mt.h"
#include <stdio.h>
#include <errno.h>
#include <rpc/rpc.h>
#include <string.h>
#include <sys/param.h>
#include <stdlib.h>
#include <unistd.h>
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
#endif
#ifndef NETIDLEN
#define NETIDLEN 32
#endif
struct rpc_call_private {
int valid;
CLIENT *client;
pid_t pid;
rpcprog_t prognum;
rpcvers_t versnum;
char host[MAXHOSTNAMELEN];
char nettype[NETIDLEN];
};
static void
rpc_call_destroy(void *vp)
{
struct rpc_call_private *rcp = (struct rpc_call_private *)vp;
if (rcp) {
if (rcp->client)
CLNT_DESTROY(rcp->client);
free(rcp);
}
}
enum clnt_stat
rpc_call(const char *host, const rpcprog_t prognum, const rpcvers_t versnum,
const rpcproc_t procnum, const xdrproc_t inproc, const char *in,
const xdrproc_t outproc, char *out, const char *netclass)
{
struct rpc_call_private *rcp;
enum clnt_stat clnt_stat;
struct timeval timeout, tottimeout;
static pthread_key_t rpc_call_key = PTHREAD_ONCE_KEY_NP;
char nettype_array[NETIDLEN];
char *nettype = &nettype_array[0];
if (netclass == NULL)
nettype = NULL;
else {
size_t len = strlen(netclass);
if (len >= sizeof (nettype_array)) {
rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
return (rpc_createerr.cf_stat);
}
(void) strcpy(nettype, netclass);
}
rcp = thr_get_storage(&rpc_call_key, sizeof (*rcp), rpc_call_destroy);
if (rcp == NULL) {
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
rpc_createerr.cf_error.re_errno = errno;
return (rpc_createerr.cf_stat);
}
if ((nettype == NULL) || (nettype[0] == '\0'))
nettype = "netpath";
if (!(rcp->valid &&
rcp->pid == getpid() &&
rcp->prognum == prognum &&
rcp->versnum == versnum &&
strcmp(rcp->host, host) == 0 &&
strcmp(rcp->nettype, nettype) == 0)) {
int fd;
rcp->valid = 0;
if (rcp->client)
CLNT_DESTROY(rcp->client);
rcp->client = clnt_create(host, prognum, versnum, nettype);
rcp->pid = getpid();
if (rcp->client == NULL)
return (rpc_createerr.cf_stat);
timeout.tv_usec = 0;
timeout.tv_sec = 5;
(void) CLNT_CONTROL(rcp->client,
CLSET_RETRY_TIMEOUT, (char *)&timeout);
if (CLNT_CONTROL(rcp->client, CLGET_FD, (char *)&fd))
(void) fcntl(fd, F_SETFD, 1);
rcp->prognum = prognum;
rcp->versnum = versnum;
if ((strlen(host) < (size_t)MAXHOSTNAMELEN) &&
(strlen(nettype) < (size_t)NETIDLEN)) {
(void) strcpy(rcp->host, host);
(void) strcpy(rcp->nettype, nettype);
rcp->valid = 1;
} else {
rcp->valid = 0;
}
}
tottimeout.tv_sec = 25;
tottimeout.tv_usec = 0;
clnt_stat = CLNT_CALL(rcp->client, procnum, inproc, (char *)in,
outproc, out, tottimeout);
if (clnt_stat != RPC_SUCCESS)
rcp->valid = 0;
return (clnt_stat);
}