174462Salfred/*	$NetBSD: clnt_simple.c,v 1.21 2000/07/06 03:10:34 christos Exp $	*/
274462Salfred
31901Swollman/*
41901Swollman * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
51901Swollman * unrestricted use provided that this legend is included on all tape
61901Swollman * media and as a part of the software program in whole or part.  Users
71901Swollman * may copy or modify Sun RPC without charge, but are not authorized
81901Swollman * to license or distribute it to anyone else except as part of a product or
91901Swollman * program developed by the user.
108870Srgrimes *
111901Swollman * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
121901Swollman * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
131901Swollman * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
148870Srgrimes *
151901Swollman * Sun RPC is provided with no support and without any obligation on the
161901Swollman * part of Sun Microsystems, Inc. to assist in its use, correction,
171901Swollman * modification or enhancement.
188870Srgrimes *
191901Swollman * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
201901Swollman * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
211901Swollman * OR ANY PART THEREOF.
228870Srgrimes *
231901Swollman * In no event will Sun Microsystems, Inc. be liable for any lost revenue
241901Swollman * or profits or other special, indirect and consequential damages, even if
251901Swollman * Sun has been advised of the possibility of such damages.
268870Srgrimes *
271901Swollman * Sun Microsystems, Inc.
281901Swollman * 2550 Garcia Avenue
291901Swollman * Mountain View, California  94043
301901Swollman */
3174462Salfred/*
3274462Salfred * Copyright (c) 1986-1991 by Sun Microsystems Inc.
3374462Salfred */
341901Swollman
351901Swollman#if defined(LIBC_SCCS) && !defined(lint)
36136581Sobrienstatic char *sccsid2 = "from: @(#)clnt_simple.c 1.35 87/08/11 Copyr 1984 Sun Micro";
3792990Sobrienstatic char *sccsid = "from: @(#)clnt_simple.c	2.2 88/08/01 4.0 RPCSRC";
381901Swollman#endif
3992990Sobrien#include <sys/cdefs.h>
4092990Sobrien__FBSDID("$FreeBSD$");
411901Swollman
428870Srgrimes/*
431901Swollman * clnt_simple.c
4474462Salfred * Simplified front end to client rpc.
451901Swollman *
461901Swollman */
471901Swollman
4875094Siedowse#include "namespace.h"
4974462Salfred#include "reentrant.h"
5021070Speter#include <sys/param.h>
511901Swollman#include <stdio.h>
5274462Salfred#include <errno.h>
5374462Salfred#include <rpc/rpc.h>
5474462Salfred#include <string.h>
551901Swollman#include <stdlib.h>
5674462Salfred#include <fcntl.h>
5711666Sphk#include <unistd.h>
5871579Sdeischen#include "un-namespace.h"
59156090Sdeischen#include "mt_misc.h"
601901Swollman
6174462Salfred#ifndef MAXHOSTNAMELEN
6274462Salfred#define	MAXHOSTNAMELEN 64
6374462Salfred#endif
641901Swollman
6574462Salfred#ifndef NETIDLEN
6674462Salfred#define	NETIDLEN 32
6774462Salfred#endif
6874462Salfred
6974462Salfredstruct rpc_call_private {
7074462Salfred	int	valid;			/* Is this entry valid ? */
7174462Salfred	CLIENT	*client;		/* Client handle */
7274462Salfred	pid_t	pid;			/* process-id at moment of creation */
7374462Salfred	rpcprog_t prognum;		/* Program */
7474462Salfred	rpcvers_t versnum;		/* Version */
7574462Salfred	char	host[MAXHOSTNAMELEN];	/* Servers host */
7674462Salfred	char	nettype[NETIDLEN];	/* Network type */
7774462Salfred};
7874462Salfredstatic struct rpc_call_private *rpc_call_private_main;
79204950Sjhbstatic thread_key_t rpc_call_key;
80204950Sjhbstatic once_t rpc_call_once = ONCE_INITIALIZER;
81204950Sjhbstatic int rpc_call_key_error;
8274462Salfred
83204950Sjhbstatic void rpc_call_key_init(void);
8492905Sobrienstatic void rpc_call_destroy(void *);
8574462Salfred
8674462Salfredstatic void
8774462Salfredrpc_call_destroy(void *vp)
881901Swollman{
8974462Salfred	struct rpc_call_private *rcp = (struct rpc_call_private *)vp;
9074462Salfred
9174462Salfred	if (rcp) {
9274462Salfred		if (rcp->client)
9374462Salfred			CLNT_DESTROY(rcp->client);
9474462Salfred		free(rcp);
9574462Salfred	}
9674462Salfred}
9774462Salfred
98204950Sjhbstatic void
99204950Sjhbrpc_call_key_init(void)
100204950Sjhb{
101204950Sjhb
102204950Sjhb	rpc_call_key_error = thr_keycreate(&rpc_call_key, rpc_call_destroy);
103204950Sjhb}
104204950Sjhb
10574462Salfred/*
10674462Salfred * This is the simplified interface to the client rpc layer.
10774462Salfred * The client handle is not destroyed here and is reused for
10874462Salfred * the future calls to same prog, vers, host and nettype combination.
10974462Salfred *
11074462Salfred * The total time available is 25 seconds.
11174462Salfred */
11274462Salfredenum clnt_stat
11374462Salfredrpc_call(host, prognum, versnum, procnum, inproc, in, outproc, out, nettype)
11474462Salfred	const char *host;			/* host name */
11574462Salfred	rpcprog_t prognum;			/* program number */
11674462Salfred	rpcvers_t versnum;			/* version number */
11774462Salfred	rpcproc_t procnum;			/* procedure number */
11874462Salfred	xdrproc_t inproc, outproc;	/* in/out XDR procedures */
11974462Salfred	const char *in;
12074462Salfred	char  *out;			/* recv/send data */
12174462Salfred	const char *nettype;			/* nettype */
12274462Salfred{
12374462Salfred	struct rpc_call_private *rcp = (struct rpc_call_private *) 0;
1241901Swollman	enum clnt_stat clnt_stat;
1251901Swollman	struct timeval timeout, tottimeout;
12674462Salfred	int main_thread = 1;
1271901Swollman
12874462Salfred	if ((main_thread = thr_main())) {
12974462Salfred		rcp = rpc_call_private_main;
13074462Salfred	} else {
131204950Sjhb		if (thr_once(&rpc_call_once, rpc_call_key_init) != 0 ||
132204950Sjhb		    rpc_call_key_error != 0) {
133204950Sjhb			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
134204950Sjhb			rpc_createerr.cf_error.re_errno = rpc_call_key_error;
135204950Sjhb			return (rpc_createerr.cf_stat);
13674462Salfred		}
13774462Salfred		rcp = (struct rpc_call_private *)thr_getspecific(rpc_call_key);
1381901Swollman	}
13974462Salfred	if (rcp == NULL) {
14074462Salfred		rcp = malloc(sizeof (*rcp));
14174462Salfred		if (rcp == NULL) {
14274462Salfred			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
14374462Salfred			rpc_createerr.cf_error.re_errno = errno;
14474462Salfred			return (rpc_createerr.cf_stat);
14574462Salfred		}
14674462Salfred		if (main_thread)
14774462Salfred			rpc_call_private_main = rcp;
14874462Salfred		else
14974462Salfred			thr_setspecific(rpc_call_key, (void *) rcp);
15074462Salfred		rcp->valid = 0;
15174462Salfred		rcp->client = NULL;
1521901Swollman	}
153121651Smbr	if ((nettype == NULL) || (nettype[0] == 0))
15474462Salfred		nettype = "netpath";
15574462Salfred	if (!(rcp->valid && rcp->pid == getpid() &&
15674462Salfred		(rcp->prognum == prognum) &&
15774462Salfred		(rcp->versnum == versnum) &&
15874462Salfred		(!strcmp(rcp->host, host)) &&
15974462Salfred		(!strcmp(rcp->nettype, nettype)))) {
16074462Salfred		int fd;
16174462Salfred
16274462Salfred		rcp->valid = 0;
16374462Salfred		if (rcp->client)
16474462Salfred			CLNT_DESTROY(rcp->client);
16574462Salfred		/*
16674462Salfred		 * Using the first successful transport for that type
16774462Salfred		 */
16874462Salfred		rcp->client = clnt_create(host, prognum, versnum, nettype);
16974462Salfred		rcp->pid = getpid();
17074462Salfred		if (rcp->client == NULL) {
17174462Salfred			return (rpc_createerr.cf_stat);
1721901Swollman		}
17374462Salfred		/*
17474462Salfred		 * Set time outs for connectionless case.  Do it
17574462Salfred		 * unconditionally.  Faster than doing a t_getinfo()
17674462Salfred		 * and then doing the right thing.
17774462Salfred		 */
1781901Swollman		timeout.tv_usec = 0;
1791901Swollman		timeout.tv_sec = 5;
18074462Salfred		(void) CLNT_CONTROL(rcp->client,
18174462Salfred				CLSET_RETRY_TIMEOUT, (char *)(void *)&timeout);
18274462Salfred		if (CLNT_CONTROL(rcp->client, CLGET_FD, (char *)(void *)&fd))
18374462Salfred			_fcntl(fd, F_SETFD, 1);	/* make it "close on exec" */
18474462Salfred		rcp->prognum = prognum;
18574462Salfred		rcp->versnum = versnum;
18674462Salfred		if ((strlen(host) < (size_t)MAXHOSTNAMELEN) &&
18774462Salfred		    (strlen(nettype) < (size_t)NETIDLEN)) {
18874462Salfred			(void) strcpy(rcp->host, host);
18974462Salfred			(void) strcpy(rcp->nettype, nettype);
19074462Salfred			rcp->valid = 1;
19174462Salfred		} else {
19274462Salfred			rcp->valid = 0;
19374462Salfred		}
19474462Salfred	} /* else reuse old client */
1951901Swollman	tottimeout.tv_sec = 25;
1961901Swollman	tottimeout.tv_usec = 0;
19774462Salfred	/*LINTED const castaway*/
19874462Salfred	clnt_stat = CLNT_CALL(rcp->client, procnum, inproc, (char *) in,
1991901Swollman	    outproc, out, tottimeout);
2008870Srgrimes	/*
2011901Swollman	 * if call failed, empty cache
2021901Swollman	 */
2031901Swollman	if (clnt_stat != RPC_SUCCESS)
20474462Salfred		rcp->valid = 0;
20574462Salfred	return (clnt_stat);
2061901Swollman}
207