174462Salfred/*	$NetBSD: clnt_simple.c,v 1.21 2000/07/06 03:10:34 christos Exp $	*/
274462Salfred
3261057Smav/*-
4261057Smav * Copyright (c) 2009, Sun Microsystems, Inc.
5261057Smav * All rights reserved.
68870Srgrimes *
7261057Smav * Redistribution and use in source and binary forms, with or without
8261057Smav * modification, are permitted provided that the following conditions are met:
9261057Smav * - Redistributions of source code must retain the above copyright notice,
10261057Smav *   this list of conditions and the following disclaimer.
11261057Smav * - Redistributions in binary form must reproduce the above copyright notice,
12261057Smav *   this list of conditions and the following disclaimer in the documentation
13261057Smav *   and/or other materials provided with the distribution.
14261057Smav * - Neither the name of Sun Microsystems, Inc. nor the names of its
15261057Smav *   contributors may be used to endorse or promote products derived
16261057Smav *   from this software without specific prior written permission.
17261057Smav *
18261057Smav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19261057Smav * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20261057Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21261057Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22261057Smav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23261057Smav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24261057Smav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25261057Smav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26261057Smav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27261057Smav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28261057Smav * POSSIBILITY OF SUCH DAMAGE.
291901Swollman */
3074462Salfred/*
3174462Salfred * Copyright (c) 1986-1991 by Sun Microsystems Inc.
3274462Salfred */
331901Swollman
341901Swollman#if defined(LIBC_SCCS) && !defined(lint)
35136581Sobrienstatic char *sccsid2 = "from: @(#)clnt_simple.c 1.35 87/08/11 Copyr 1984 Sun Micro";
3692990Sobrienstatic char *sccsid = "from: @(#)clnt_simple.c	2.2 88/08/01 4.0 RPCSRC";
371901Swollman#endif
3892990Sobrien#include <sys/cdefs.h>
3992990Sobrien__FBSDID("$FreeBSD$");
401901Swollman
418870Srgrimes/*
421901Swollman * clnt_simple.c
4374462Salfred * Simplified front end to client rpc.
441901Swollman *
451901Swollman */
461901Swollman
4775094Siedowse#include "namespace.h"
4874462Salfred#include "reentrant.h"
4921070Speter#include <sys/param.h>
501901Swollman#include <stdio.h>
5174462Salfred#include <errno.h>
5274462Salfred#include <rpc/rpc.h>
5374462Salfred#include <string.h>
541901Swollman#include <stdlib.h>
5574462Salfred#include <fcntl.h>
5611666Sphk#include <unistd.h>
5771579Sdeischen#include "un-namespace.h"
58156090Sdeischen#include "mt_misc.h"
591901Swollman
6074462Salfred#ifndef MAXHOSTNAMELEN
6174462Salfred#define	MAXHOSTNAMELEN 64
6274462Salfred#endif
631901Swollman
6474462Salfred#ifndef NETIDLEN
6574462Salfred#define	NETIDLEN 32
6674462Salfred#endif
6774462Salfred
6874462Salfredstruct rpc_call_private {
6974462Salfred	int	valid;			/* Is this entry valid ? */
7074462Salfred	CLIENT	*client;		/* Client handle */
7174462Salfred	pid_t	pid;			/* process-id at moment of creation */
7274462Salfred	rpcprog_t prognum;		/* Program */
7374462Salfred	rpcvers_t versnum;		/* Version */
7474462Salfred	char	host[MAXHOSTNAMELEN];	/* Servers host */
7574462Salfred	char	nettype[NETIDLEN];	/* Network type */
7674462Salfred};
7774462Salfredstatic struct rpc_call_private *rpc_call_private_main;
78204950Sjhbstatic thread_key_t rpc_call_key;
79204950Sjhbstatic once_t rpc_call_once = ONCE_INITIALIZER;
80204950Sjhbstatic int rpc_call_key_error;
8174462Salfred
82204950Sjhbstatic void rpc_call_key_init(void);
8392905Sobrienstatic void rpc_call_destroy(void *);
8474462Salfred
8574462Salfredstatic void
8674462Salfredrpc_call_destroy(void *vp)
871901Swollman{
8874462Salfred	struct rpc_call_private *rcp = (struct rpc_call_private *)vp;
8974462Salfred
9074462Salfred	if (rcp) {
9174462Salfred		if (rcp->client)
9274462Salfred			CLNT_DESTROY(rcp->client);
9374462Salfred		free(rcp);
9474462Salfred	}
9574462Salfred}
9674462Salfred
97204950Sjhbstatic void
98204950Sjhbrpc_call_key_init(void)
99204950Sjhb{
100204950Sjhb
101204950Sjhb	rpc_call_key_error = thr_keycreate(&rpc_call_key, rpc_call_destroy);
102204950Sjhb}
103204950Sjhb
10474462Salfred/*
10574462Salfred * This is the simplified interface to the client rpc layer.
10674462Salfred * The client handle is not destroyed here and is reused for
10774462Salfred * the future calls to same prog, vers, host and nettype combination.
10874462Salfred *
10974462Salfred * The total time available is 25 seconds.
11074462Salfred */
11174462Salfredenum clnt_stat
11274462Salfredrpc_call(host, prognum, versnum, procnum, inproc, in, outproc, out, nettype)
11374462Salfred	const char *host;			/* host name */
11474462Salfred	rpcprog_t prognum;			/* program number */
11574462Salfred	rpcvers_t versnum;			/* version number */
11674462Salfred	rpcproc_t procnum;			/* procedure number */
11774462Salfred	xdrproc_t inproc, outproc;	/* in/out XDR procedures */
11874462Salfred	const char *in;
11974462Salfred	char  *out;			/* recv/send data */
12074462Salfred	const char *nettype;			/* nettype */
12174462Salfred{
12274462Salfred	struct rpc_call_private *rcp = (struct rpc_call_private *) 0;
1231901Swollman	enum clnt_stat clnt_stat;
1241901Swollman	struct timeval timeout, tottimeout;
12574462Salfred	int main_thread = 1;
1261901Swollman
12774462Salfred	if ((main_thread = thr_main())) {
12874462Salfred		rcp = rpc_call_private_main;
12974462Salfred	} else {
130204950Sjhb		if (thr_once(&rpc_call_once, rpc_call_key_init) != 0 ||
131204950Sjhb		    rpc_call_key_error != 0) {
132204950Sjhb			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
133204950Sjhb			rpc_createerr.cf_error.re_errno = rpc_call_key_error;
134204950Sjhb			return (rpc_createerr.cf_stat);
13574462Salfred		}
13674462Salfred		rcp = (struct rpc_call_private *)thr_getspecific(rpc_call_key);
1371901Swollman	}
13874462Salfred	if (rcp == NULL) {
13974462Salfred		rcp = malloc(sizeof (*rcp));
14074462Salfred		if (rcp == NULL) {
14174462Salfred			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
14274462Salfred			rpc_createerr.cf_error.re_errno = errno;
14374462Salfred			return (rpc_createerr.cf_stat);
14474462Salfred		}
14574462Salfred		if (main_thread)
14674462Salfred			rpc_call_private_main = rcp;
14774462Salfred		else
14874462Salfred			thr_setspecific(rpc_call_key, (void *) rcp);
14974462Salfred		rcp->valid = 0;
15074462Salfred		rcp->client = NULL;
1511901Swollman	}
152121651Smbr	if ((nettype == NULL) || (nettype[0] == 0))
15374462Salfred		nettype = "netpath";
15474462Salfred	if (!(rcp->valid && rcp->pid == getpid() &&
15574462Salfred		(rcp->prognum == prognum) &&
15674462Salfred		(rcp->versnum == versnum) &&
15774462Salfred		(!strcmp(rcp->host, host)) &&
15874462Salfred		(!strcmp(rcp->nettype, nettype)))) {
15974462Salfred		int fd;
16074462Salfred
16174462Salfred		rcp->valid = 0;
16274462Salfred		if (rcp->client)
16374462Salfred			CLNT_DESTROY(rcp->client);
16474462Salfred		/*
16574462Salfred		 * Using the first successful transport for that type
16674462Salfred		 */
16774462Salfred		rcp->client = clnt_create(host, prognum, versnum, nettype);
16874462Salfred		rcp->pid = getpid();
16974462Salfred		if (rcp->client == NULL) {
17074462Salfred			return (rpc_createerr.cf_stat);
1711901Swollman		}
17274462Salfred		/*
17374462Salfred		 * Set time outs for connectionless case.  Do it
17474462Salfred		 * unconditionally.  Faster than doing a t_getinfo()
17574462Salfred		 * and then doing the right thing.
17674462Salfred		 */
1771901Swollman		timeout.tv_usec = 0;
1781901Swollman		timeout.tv_sec = 5;
17974462Salfred		(void) CLNT_CONTROL(rcp->client,
18074462Salfred				CLSET_RETRY_TIMEOUT, (char *)(void *)&timeout);
18174462Salfred		if (CLNT_CONTROL(rcp->client, CLGET_FD, (char *)(void *)&fd))
18274462Salfred			_fcntl(fd, F_SETFD, 1);	/* make it "close on exec" */
18374462Salfred		rcp->prognum = prognum;
18474462Salfred		rcp->versnum = versnum;
18574462Salfred		if ((strlen(host) < (size_t)MAXHOSTNAMELEN) &&
18674462Salfred		    (strlen(nettype) < (size_t)NETIDLEN)) {
18774462Salfred			(void) strcpy(rcp->host, host);
18874462Salfred			(void) strcpy(rcp->nettype, nettype);
18974462Salfred			rcp->valid = 1;
19074462Salfred		} else {
19174462Salfred			rcp->valid = 0;
19274462Salfred		}
19374462Salfred	} /* else reuse old client */
1941901Swollman	tottimeout.tv_sec = 25;
1951901Swollman	tottimeout.tv_usec = 0;
19674462Salfred	/*LINTED const castaway*/
19774462Salfred	clnt_stat = CLNT_CALL(rcp->client, procnum, inproc, (char *) in,
1981901Swollman	    outproc, out, tottimeout);
1998870Srgrimes	/*
2001901Swollman	 * if call failed, empty cache
2011901Swollman	 */
2021901Swollman	if (clnt_stat != RPC_SUCCESS)
20374462Salfred		rcp->valid = 0;
20474462Salfred	return (clnt_stat);
2051901Swollman}
206