#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
#if 0
static char sccsid[] = "@(#)clnt_simple.c 1.49 89/01/31 Copyr 1984 Sun Micro";
#else
__RCSID("$NetBSD: clnt_simple.c,v 1.33 2015/01/20 18:31:25 christos Exp $");
#endif
#endif
#include "namespace.h"
#include "reentrant.h"
#include <sys/param.h>
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include <rpc/rpc.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#ifdef __weak_alias
__weak_alias(rpc_call,_rpc_call)
#endif
#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;
#ifdef _REENTRANT
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 thread_key_t rpc_call_key;
static once_t rpc_call_once = ONCE_INITIALIZER;
static void
rpc_call_setup(void)
{
thr_keycreate(&rpc_call_key, rpc_call_destroy);
}
#endif
enum clnt_stat
rpc_call(
const char * host,
rpcprog_t prognum,
rpcvers_t versnum,
rpcproc_t procnum,
xdrproc_t inproc,
const char * in,
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;
_DIAGASSERT(host != NULL);
#ifdef _REENTRANT
if (__isthreaded) {
thr_once(&rpc_call_once, rpc_call_setup);
rcp = thr_getspecific(rpc_call_key);
} else
#endif
rcp = rpc_call_private_main;
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);
}
#ifdef _REENTRANT
if (__isthreaded)
thr_setspecific(rpc_call_key, (void *) rcp);
else
#endif
rpc_call_private_main = 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))
(void)fcntl(fd, F_SETFD, FD_CLOEXEC);
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, in,
outproc, out, tottimeout);
if (clnt_stat != RPC_SUCCESS)
rcp->valid = 0;
return (clnt_stat);
}