#include "namespace.h"
#include "reentrant.h"
#include <sys/param.h>
#include <stdio.h>
#include <errno.h>
#include <rpc/rpc.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include "un-namespace.h"
#include "mt_misc.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 struct rpc_call_private *rpc_call_private_main;
static thread_key_t rpc_call_key;
static once_t rpc_call_once = ONCE_INITIALIZER;
static int rpc_call_key_error;
static void rpc_call_key_init(void);
static void rpc_call_destroy(void *);
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);
}
}
static void
rpc_call_key_init(void)
{
rpc_call_key_error = thr_keycreate(&rpc_call_key, rpc_call_destroy);
}
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 *nettype)
{
struct rpc_call_private *rcp = (struct rpc_call_private *) 0;
enum clnt_stat clnt_stat;
struct timeval timeout, tottimeout;
int main_thread = 1;
if ((main_thread = thr_main())) {
rcp = rpc_call_private_main;
} else {
if (thr_once(&rpc_call_once, rpc_call_key_init) != 0 ||
rpc_call_key_error != 0) {
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
rpc_createerr.cf_error.re_errno = rpc_call_key_error;
return (rpc_createerr.cf_stat);
}
rcp = (struct rpc_call_private *)thr_getspecific(rpc_call_key);
}
if (rcp == NULL) {
rcp = malloc(sizeof (*rcp));
if (rcp == NULL) {
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
rpc_createerr.cf_error.re_errno = errno;
return (rpc_createerr.cf_stat);
}
if (main_thread)
rpc_call_private_main = rcp;
else
thr_setspecific(rpc_call_key, (void *) rcp);
rcp->valid = 0;
rcp->client = NULL;
}
if ((nettype == NULL) || (nettype[0] == 0))
nettype = "netpath";
if (!(rcp->valid && rcp->pid == getpid() &&
(rcp->prognum == prognum) &&
(rcp->versnum == versnum) &&
(!strcmp(rcp->host, host)) &&
(!strcmp(rcp->nettype, nettype)))) {
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 *)(void *)&timeout);
if (CLNT_CONTROL(rcp->client, CLGET_FD, (char *)(void *)&fd))
_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);
}