1*26ba8048Schristos /* $NetBSD: clnt_simple.c,v 1.33 2015/01/20 18:31:25 christos Exp $ */
29e15c989Scgd
363d7b677Scgd /*
447c0e0c3Stron * Copyright (c) 2010, Oracle America, Inc.
563d7b677Scgd *
647c0e0c3Stron * Redistribution and use in source and binary forms, with or without
747c0e0c3Stron * modification, are permitted provided that the following conditions are
847c0e0c3Stron * met:
963d7b677Scgd *
1047c0e0c3Stron * * Redistributions of source code must retain the above copyright
1147c0e0c3Stron * notice, this list of conditions and the following disclaimer.
1247c0e0c3Stron * * Redistributions in binary form must reproduce the above
1347c0e0c3Stron * copyright notice, this list of conditions and the following
1447c0e0c3Stron * disclaimer in the documentation and/or other materials
1547c0e0c3Stron * provided with the distribution.
1647c0e0c3Stron * * Neither the name of the "Oracle America, Inc." nor the names of its
1747c0e0c3Stron * contributors may be used to endorse or promote products derived
1847c0e0c3Stron * from this software without specific prior written permission.
1963d7b677Scgd *
2047c0e0c3Stron * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2147c0e0c3Stron * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2247c0e0c3Stron * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2347c0e0c3Stron * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2447c0e0c3Stron * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
2547c0e0c3Stron * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2647c0e0c3Stron * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
2747c0e0c3Stron * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2847c0e0c3Stron * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2947c0e0c3Stron * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
3047c0e0c3Stron * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3147c0e0c3Stron * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3263d7b677Scgd */
337df0ccbaSfvdl /*
347df0ccbaSfvdl * Copyright (c) 1986-1991 by Sun Microsystems Inc.
357df0ccbaSfvdl */
3663d7b677Scgd
377df0ccbaSfvdl /* #ident "@(#)clnt_simple.c 1.17 94/04/24 SMI" */
387df0ccbaSfvdl
395c945215Sitojun #include <sys/cdefs.h>
405c945215Sitojun #if defined(LIBC_SCCS) && !defined(lint)
41c63c52b2Schristos #if 0
427df0ccbaSfvdl static char sccsid[] = "@(#)clnt_simple.c 1.49 89/01/31 Copyr 1984 Sun Micro";
435c945215Sitojun #else
44*26ba8048Schristos __RCSID("$NetBSD: clnt_simple.c,v 1.33 2015/01/20 18:31:25 christos Exp $");
45c63c52b2Schristos #endif
4663d7b677Scgd #endif
4763d7b677Scgd
4863d7b677Scgd /*
4963d7b677Scgd * clnt_simple.c
507df0ccbaSfvdl * Simplified front end to client rpc.
5163d7b677Scgd *
5263d7b677Scgd */
5363d7b677Scgd
5443fa6fe3Sjtc #include "namespace.h"
557df0ccbaSfvdl #include "reentrant.h"
567df0ccbaSfvdl #include <sys/param.h>
5763d7b677Scgd #include <stdio.h>
580e8cfd8fSlukem #include <assert.h>
597df0ccbaSfvdl #include <errno.h>
607df0ccbaSfvdl #include <rpc/rpc.h>
6163d7b677Scgd #include <string.h>
627df0ccbaSfvdl #include <stdlib.h>
637df0ccbaSfvdl #include <fcntl.h>
64c63c52b2Schristos #include <unistd.h>
6546e6c5e8Slukem
6643fa6fe3Sjtc #ifdef __weak_alias
677df0ccbaSfvdl __weak_alias(rpc_call,_rpc_call)
6843fa6fe3Sjtc #endif
6943fa6fe3Sjtc
707df0ccbaSfvdl #ifndef MAXHOSTNAMELEN
717df0ccbaSfvdl #define MAXHOSTNAMELEN 64
727df0ccbaSfvdl #endif
7363d7b677Scgd
747df0ccbaSfvdl #ifndef NETIDLEN
757df0ccbaSfvdl #define NETIDLEN 32
767df0ccbaSfvdl #endif
777df0ccbaSfvdl
787df0ccbaSfvdl struct rpc_call_private {
797df0ccbaSfvdl int valid; /* Is this entry valid ? */
807df0ccbaSfvdl CLIENT *client; /* Client handle */
817df0ccbaSfvdl pid_t pid; /* process-id at moment of creation */
827df0ccbaSfvdl rpcprog_t prognum; /* Program */
837df0ccbaSfvdl rpcvers_t versnum; /* Version */
847df0ccbaSfvdl char host[MAXHOSTNAMELEN]; /* Servers host */
857df0ccbaSfvdl char nettype[NETIDLEN]; /* Network type */
867df0ccbaSfvdl };
877df0ccbaSfvdl static struct rpc_call_private *rpc_call_private_main;
887df0ccbaSfvdl
893fdac2b8Sthorpej #ifdef _REENTRANT
90adb74221Smatt static void rpc_call_destroy(void *);
917df0ccbaSfvdl
927df0ccbaSfvdl static void
rpc_call_destroy(void * vp)937df0ccbaSfvdl rpc_call_destroy(void *vp)
9463d7b677Scgd {
95deb154d2Schristos struct rpc_call_private *rcp = (struct rpc_call_private *)vp;
967df0ccbaSfvdl
977df0ccbaSfvdl if (rcp) {
987df0ccbaSfvdl if (rcp->client)
997df0ccbaSfvdl CLNT_DESTROY(rcp->client);
1007df0ccbaSfvdl free(rcp);
1017df0ccbaSfvdl }
1027df0ccbaSfvdl }
1033fdac2b8Sthorpej static thread_key_t rpc_call_key;
1043fdac2b8Sthorpej static once_t rpc_call_once = ONCE_INITIALIZER;
1053fdac2b8Sthorpej
1063fdac2b8Sthorpej static void
rpc_call_setup(void)1073fdac2b8Sthorpej rpc_call_setup(void)
1083fdac2b8Sthorpej {
1093fdac2b8Sthorpej
1103fdac2b8Sthorpej thr_keycreate(&rpc_call_key, rpc_call_destroy);
1113fdac2b8Sthorpej }
1127df0ccbaSfvdl #endif
1137df0ccbaSfvdl
1143fdac2b8Sthorpej
1157df0ccbaSfvdl /*
1167df0ccbaSfvdl * This is the simplified interface to the client rpc layer.
1177df0ccbaSfvdl * The client handle is not destroyed here and is reused for
1187df0ccbaSfvdl * the future calls to same prog, vers, host and nettype combination.
1197df0ccbaSfvdl *
1207df0ccbaSfvdl * The total time available is 25 seconds.
1217df0ccbaSfvdl */
1227df0ccbaSfvdl 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)123adb74221Smatt rpc_call(
124adb74221Smatt const char * host, /* host name */
125adb74221Smatt rpcprog_t prognum, /* program number */
126adb74221Smatt rpcvers_t versnum, /* version number */
127adb74221Smatt rpcproc_t procnum, /* procedure number */
128adb74221Smatt xdrproc_t inproc, /* in XDR procedures */
129adb74221Smatt const char * in, /* recv data */
130adb74221Smatt xdrproc_t outproc, /* out XDR procedures */
131adb74221Smatt char * out, /* send data */
132adb74221Smatt const char * nettype) /* nettype */
1337df0ccbaSfvdl {
1347df0ccbaSfvdl struct rpc_call_private *rcp = (struct rpc_call_private *) 0;
13563d7b677Scgd enum clnt_stat clnt_stat;
13663d7b677Scgd struct timeval timeout, tottimeout;
13763d7b677Scgd
1380e8cfd8fSlukem _DIAGASSERT(host != NULL);
1390e8cfd8fSlukem /* XXX: in may be NULL ??? */
1400e8cfd8fSlukem /* XXX: out may be NULL ??? */
1410e8cfd8fSlukem /* XXX: nettype may be NULL ??? */
1420e8cfd8fSlukem
1433fdac2b8Sthorpej #ifdef _REENTRANT
144*26ba8048Schristos if (__isthreaded) {
1453fdac2b8Sthorpej thr_once(&rpc_call_once, rpc_call_setup);
1463fdac2b8Sthorpej rcp = thr_getspecific(rpc_call_key);
147*26ba8048Schristos } else
1487df0ccbaSfvdl #endif
149*26ba8048Schristos rcp = rpc_call_private_main;
150deb154d2Schristos if (rcp == NULL) {
151deb154d2Schristos rcp = malloc(sizeof (*rcp));
152deb154d2Schristos if (rcp == NULL) {
1537df0ccbaSfvdl rpc_createerr.cf_stat = RPC_SYSTEMERROR;
1547df0ccbaSfvdl rpc_createerr.cf_error.re_errno = errno;
1557df0ccbaSfvdl return (rpc_createerr.cf_stat);
1567df0ccbaSfvdl }
157*26ba8048Schristos #ifdef _REENTRANT
158*26ba8048Schristos if (__isthreaded)
1597df0ccbaSfvdl thr_setspecific(rpc_call_key, (void *) rcp);
160*26ba8048Schristos else
161*26ba8048Schristos #endif
162*26ba8048Schristos rpc_call_private_main = rcp;
1637df0ccbaSfvdl rcp->valid = 0;
1647df0ccbaSfvdl rcp->client = NULL;
1657df0ccbaSfvdl }
16639d7a2e3Sfvdl if ((nettype == NULL) || (nettype[0] == 0))
1677df0ccbaSfvdl nettype = "netpath";
1687df0ccbaSfvdl if (!(rcp->valid && rcp->pid == getpid() &&
1697df0ccbaSfvdl (rcp->prognum == prognum) &&
1707df0ccbaSfvdl (rcp->versnum == versnum) &&
1717df0ccbaSfvdl (!strcmp(rcp->host, host)) &&
1727df0ccbaSfvdl (!strcmp(rcp->nettype, nettype)))) {
1737df0ccbaSfvdl int fd;
1747df0ccbaSfvdl
1757df0ccbaSfvdl rcp->valid = 0;
1767df0ccbaSfvdl if (rcp->client)
1777df0ccbaSfvdl CLNT_DESTROY(rcp->client);
1787df0ccbaSfvdl /*
1797df0ccbaSfvdl * Using the first successful transport for that type
1807df0ccbaSfvdl */
1817df0ccbaSfvdl rcp->client = clnt_create(host, prognum, versnum, nettype);
1827df0ccbaSfvdl rcp->pid = getpid();
183deb154d2Schristos if (rcp->client == NULL) {
1847df0ccbaSfvdl return (rpc_createerr.cf_stat);
1857df0ccbaSfvdl }
1867df0ccbaSfvdl /*
1877df0ccbaSfvdl * Set time outs for connectionless case. Do it
1887df0ccbaSfvdl * unconditionally. Faster than doing a t_getinfo()
1897df0ccbaSfvdl * and then doing the right thing.
1907df0ccbaSfvdl */
19163d7b677Scgd timeout.tv_usec = 0;
19263d7b677Scgd timeout.tv_sec = 5;
1937df0ccbaSfvdl (void) CLNT_CONTROL(rcp->client,
194deb154d2Schristos CLSET_RETRY_TIMEOUT, (char *)(void *)&timeout);
195deb154d2Schristos if (CLNT_CONTROL(rcp->client, CLGET_FD, (char *)(void *)&fd))
19667657e2fSchristos (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
1977df0ccbaSfvdl rcp->prognum = prognum;
1987df0ccbaSfvdl rcp->versnum = versnum;
1997df0ccbaSfvdl if ((strlen(host) < (size_t)MAXHOSTNAMELEN) &&
2007df0ccbaSfvdl (strlen(nettype) < (size_t)NETIDLEN)) {
2017df0ccbaSfvdl (void) strcpy(rcp->host, host);
2027df0ccbaSfvdl (void) strcpy(rcp->nettype, nettype);
2037df0ccbaSfvdl rcp->valid = 1;
2047df0ccbaSfvdl } else {
2057df0ccbaSfvdl rcp->valid = 0;
20663d7b677Scgd }
2077df0ccbaSfvdl } /* else reuse old client */
20863d7b677Scgd tottimeout.tv_sec = 25;
20963d7b677Scgd tottimeout.tv_usec = 0;
210347f995cSyamt clnt_stat = CLNT_CALL(rcp->client, procnum, inproc, in,
211deb154d2Schristos outproc, out, tottimeout);
21263d7b677Scgd /*
21363d7b677Scgd * if call failed, empty cache
21463d7b677Scgd */
21563d7b677Scgd if (clnt_stat != RPC_SUCCESS)
2167df0ccbaSfvdl rcp->valid = 0;
2177df0ccbaSfvdl return (clnt_stat);
21863d7b677Scgd }
219