| /* |
| * Copyright (c) 2009, Sun Microsystems, Inc. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * - Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * - Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * - Neither the name of Sun Microsystems, Inc. nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| */ |
| /* |
| * Copyright (c) 1986-1991 by Sun Microsystems Inc. |
| */ |
| |
| #include <config.h> |
| #include <sys/cdefs.h> |
| |
| /* |
| * clnt_simple.c |
| * Simplified front end to client rpc. |
| */ |
| #include <pthread.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 <rpc/clnt.h> |
| |
| #ifndef MAXHOSTNAMELEN |
| #define MAXHOSTNAMELEN 64 |
| #endif |
| |
| #ifndef NETIDLEN |
| #define NETIDLEN 32 |
| #endif |
| |
| struct rpc_call_private { |
| int valid; /* Is this entry valid ? */ |
| CLIENT *client; /* Client handle */ |
| AUTH *auth; |
| pid_t pid; /* process-id at moment of creation */ |
| rpcprog_t prognum; /* Program */ |
| rpcvers_t versnum; /* Version */ |
| char host[MAXHOSTNAMELEN]; /* Servers host */ |
| char nettype[NETIDLEN]; /* Network type */ |
| }; |
| |
| 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); |
| mem_free(rcp, sizeof(*rcp)); |
| } |
| } |
| |
| /* |
| * This is the simplified interface to the client rpc layer. |
| * The client handle is not destroyed here and is reused for |
| * the future calls to same prog, vers, host and nettype combination. |
| * |
| * The total time available is 25 seconds. |
| */ |
| enum clnt_stat |
| rpc_call(const char *host, /* host name */ |
| rpcprog_t prognum, /* program number */ |
| rpcvers_t versnum, /* version number */ |
| rpcproc_t procnum, /* procedure number */ |
| xdrproc_t inproc, /* in XDR procedure */ |
| const char *in, xdrproc_t outproc, /* out XDR procedure */ |
| char *out, /* recv/send data */ |
| const char *nettype /* nettype */) |
| { |
| struct rpc_call_private *rcp = (struct rpc_call_private *)0; |
| enum clnt_stat clnt_stat; |
| struct timeval timeout, tottimeout; |
| extern thread_key_t rpc_call_key; |
| extern mutex_t tsd_lock; |
| |
| if (rpc_call_key == -1) { |
| mutex_lock(&tsd_lock); |
| if (rpc_call_key == -1) |
| thr_keycreate(&rpc_call_key, rpc_call_destroy); |
| mutex_unlock(&tsd_lock); |
| } |
| rcp = (struct rpc_call_private *)thr_getspecific(rpc_call_key); |
| if (rcp == NULL) { |
| rcp = mem_alloc(sizeof(*rcp)); |
| 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); |
| /* |
| * Using the first successful transport for that type |
| */ |
| rcp->client = clnt_ncreate(host, prognum, versnum, nettype); |
| rcp->pid = getpid(); |
| if (rcp->client == NULL) |
| return (rpc_createerr.cf_stat); |
| |
| /* Create null auth handle--idempotent */ |
| rcp->auth = authnone_create(); |
| |
| /* |
| * Set time outs for connectionless case. Do it |
| * unconditionally. Faster than doing a t_getinfo() |
| * and then doing the right thing. |
| */ |
| 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); /* make it "close on exec" */ |
| 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; |
| } |
| } /* else reuse old client */ |
| tottimeout.tv_sec = 25; |
| tottimeout.tv_usec = 0; |
| |
| /* LINTED const castaway */ |
| clnt_stat = |
| CLNT_CALL(rcp->client, rcp->auth, procnum, inproc, (char *)in, |
| outproc, out, tottimeout); |
| /* |
| * if call failed, empty cache |
| */ |
| if (clnt_stat != RPC_SUCCESS) |
| rcp->valid = 0; |
| return (clnt_stat); |
| } |