clnt_rc.c revision 178112
1125699Spjd/*-
2163872Spjd * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
3125699Spjd * Authors: Doug Rabson <dfr@rabson.org>
4125699Spjd * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
5125699Spjd *
6125699Spjd * Redistribution and use in source and binary forms, with or without
7125699Spjd * modification, are permitted provided that the following conditions
8125699Spjd * are met:
9125699Spjd * 1. Redistributions of source code must retain the above copyright
10125699Spjd *    notice, this list of conditions and the following disclaimer.
11125699Spjd * 2. Redistributions in binary form must reproduce the above copyright
12125699Spjd *    notice, this list of conditions and the following disclaimer in the
13125699Spjd *    documentation and/or other materials provided with the distribution.
14125699Spjd *
15125699Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16125699Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17125699Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18125699Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19125699Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20125699Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21125699Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22125699Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23125699Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24125699Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25125699Spjd * SUCH DAMAGE.
26125699Spjd */
27163872Spjd
28131689Sru#include <sys/cdefs.h>
29125699Spjd__FBSDID("$FreeBSD: head/sys/rpc/clnt_rc.c 178112 2008-04-11 10:34:59Z dfr $");
30125699Spjd
31125699Spjd#include <sys/param.h>
32125699Spjd#include <sys/systm.h>
33125714Spjd#include <sys/lock.h>
34125714Spjd#include <sys/malloc.h>
35129381Sle#include <sys/mbuf.h>
36125699Spjd#include <sys/mutex.h>
37125699Spjd#include <sys/pcpu.h>
38125699Spjd#include <sys/proc.h>
39125699Spjd#include <sys/socket.h>
40125699Spjd#include <sys/socketvar.h>
41125699Spjd#include <sys/time.h>
42163872Spjd#include <sys/uio.h>
43163872Spjd
44125699Spjd#include <rpc/rpc.h>
45163872Spjd#include <rpc/rpc_com.h>
46163872Spjd
47125699Spjdstatic enum clnt_stat clnt_reconnect_call(CLIENT *, rpcproc_t,
48125699Spjd    xdrproc_t, void *, xdrproc_t, void *, struct timeval);
49125714Spjdstatic void clnt_reconnect_geterr(CLIENT *, struct rpc_err *);
50125714Spjdstatic bool_t clnt_reconnect_freeres(CLIENT *, xdrproc_t, void *);
51125699Spjdstatic void clnt_reconnect_abort(CLIENT *);
52129381Slestatic bool_t clnt_reconnect_control(CLIENT *, u_int, void *);
53131689Srustatic void clnt_reconnect_destroy(CLIENT *);
54129381Sle
55129381Slestatic struct clnt_ops clnt_reconnect_ops = {
56125699Spjd	.cl_call =	clnt_reconnect_call,
57125699Spjd	.cl_abort =	clnt_reconnect_abort,
58129381Sle	.cl_geterr =	clnt_reconnect_geterr,
59125699Spjd	.cl_freeres =	clnt_reconnect_freeres,
60131689Sru	.cl_destroy =	clnt_reconnect_destroy,
61125699Spjd	.cl_control =	clnt_reconnect_control
62129381Sle};
63125699Spjd
64129381Slestruct rc_data {
65125699Spjd	struct sockaddr_storage	rc_addr; /* server address */
66129381Sle	struct netconfig*	rc_nconf; /* network type */
67125699Spjd	rpcprog_t		rc_prog;  /* program number */
68125699Spjd	rpcvers_t		rc_vers;  /* version number */
69125699Spjd	size_t			rc_sendsz;
70125699Spjd	size_t			rc_recvsz;
71125699Spjd	struct timeval		rc_timeout;
72125699Spjd	struct timeval		rc_retry;
73129387Sle	const char		*rc_waitchan;
74125699Spjd	int			rc_intr;
75125699Spjd	CLIENT*			rc_client; /* underlying RPC client */
76125699Spjd};
77125699Spjd
78163870SpjdCLIENT *
79163873Spjdclnt_reconnect_create(
80125699Spjd	struct netconfig *nconf,	/* network type */
81125699Spjd	struct sockaddr *svcaddr,	/* servers address */
82125699Spjd	rpcprog_t program,		/* program number */
83133142Spjd	rpcvers_t version,		/* version number */
84125699Spjd	size_t sendsz,			/* buffer recv size */
85125699Spjd	size_t recvsz)			/* buffer send size */
86129381Sle{
87129381Sle	CLIENT *cl = NULL;		/* client handle */
88125699Spjd	struct rc_data *rc = NULL;	/* private data */
89125699Spjd
90125699Spjd	if (svcaddr == NULL) {
91133142Spjd		rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
92133142Spjd		return (NULL);
93133142Spjd	}
94133142Spjd
95133142Spjd	cl = mem_alloc(sizeof (CLIENT));
96133142Spjd	rc = mem_alloc(sizeof (*rc));
97133142Spjd	(void) memcpy(&rc->rc_addr, svcaddr, (size_t)svcaddr->sa_len);
98133142Spjd	rc->rc_nconf = nconf;
99125699Spjd	rc->rc_prog = program;
100131689Sru	rc->rc_vers = version;
101131689Sru	rc->rc_sendsz = sendsz;
102131689Sru	rc->rc_recvsz = recvsz;
103125699Spjd	rc->rc_timeout.tv_sec = -1;
104129381Sle	rc->rc_timeout.tv_usec = -1;
105125699Spjd	rc->rc_retry.tv_sec = 15;
106133142Spjd	rc->rc_retry.tv_usec = 0;
107125699Spjd	rc->rc_waitchan = "rpcrecv";
108133142Spjd	rc->rc_intr = 0;
109125699Spjd	rc->rc_client = NULL;
110133142Spjd
111125699Spjd	cl->cl_ops = &clnt_reconnect_ops;
112133142Spjd	cl->cl_private = (caddr_t)(void *)rc;
113125699Spjd	cl->cl_auth = authnone_create();
114131689Sru	cl->cl_tp = NULL;
115131689Sru	cl->cl_netid = NULL;
116131689Sru	return (cl);
117125699Spjd}
118125699Spjd
119125699Spjdstatic enum clnt_stat
120131689Sruclnt_reconnect_connect(CLIENT *cl)
121125699Spjd{
122131689Sru	struct rc_data *rc = (struct rc_data *)cl->cl_private;
123125699Spjd	struct socket *so;
124125699Spjd	int one = 1;
125125699Spjd
126125699Spjd	so = __rpc_nconf2socket(rc->rc_nconf);
127125699Spjd	if (!so) {
128125699Spjd		rpc_createerr.cf_stat = RPC_TLIERROR;
129131689Sru		rpc_createerr.cf_error.re_errno = 0;
130131689Sru		return (RPC_TLIERROR);
131131689Sru	}
132125699Spjd
133131689Sru	if (rc->rc_nconf->nc_semantics == NC_TPI_CLTS)
134131689Sru		rc->rc_client = clnt_dg_create(so,
135131689Sru		    (struct sockaddr *) &rc->rc_addr, rc->rc_prog, rc->rc_vers,
136125699Spjd		    rc->rc_sendsz, rc->rc_recvsz);
137131689Sru	else
138131689Sru		rc->rc_client = clnt_vc_create(so,
139125699Spjd		    (struct sockaddr *) &rc->rc_addr, rc->rc_prog, rc->rc_vers,
140125699Spjd		    rc->rc_sendsz, rc->rc_recvsz);
141125699Spjd
142125699Spjd	if (!rc->rc_client)
143125699Spjd		return (rpc_createerr.cf_stat);
144125699Spjd
145125699Spjd	CLNT_CONTROL(rc->rc_client, CLSET_FD_CLOSE, 0);
146125699Spjd	CLNT_CONTROL(rc->rc_client, CLSET_CONNECT, &one);
147163872Spjd	CLNT_CONTROL(rc->rc_client, CLSET_TIMEOUT, &rc->rc_timeout);
148163872Spjd	CLNT_CONTROL(rc->rc_client, CLSET_RETRY_TIMEOUT, &rc->rc_retry);
149163872Spjd	CLNT_CONTROL(rc->rc_client, CLSET_WAITCHAN, &rc->rc_waitchan);
150163872Spjd	CLNT_CONTROL(rc->rc_client, CLSET_INTERRUPTIBLE, &rc->rc_intr);
151163872Spjd
152163872Spjd	return (RPC_SUCCESS);
153163872Spjd}
154125699Spjd
155125699Spjdstatic enum clnt_stat
156125699Spjdclnt_reconnect_call(
157125699Spjd	CLIENT	*cl,			/* client handle */
158129381Sle	rpcproc_t	proc,		/* procedure number */
159125699Spjd	xdrproc_t	xargs,		/* xdr routine for args */
160129381Sle	void		*argsp,		/* pointer to args */
161125699Spjd	xdrproc_t	xresults,	/* xdr routine for results */
162125699Spjd	void		*resultsp,	/* pointer to results */
163125699Spjd	struct timeval	utimeout)	/* seconds to wait before giving up */
164125699Spjd{
165125699Spjd	struct rc_data *rc = (struct rc_data *)cl->cl_private;
166125699Spjd	enum clnt_stat stat;
167125699Spjd
168129381Sle	do {
169125699Spjd		if (!rc->rc_client) {
170125699Spjd			stat = clnt_reconnect_connect(cl);
171125699Spjd			if (stat != RPC_SUCCESS)
172129381Sle				return (stat);
173129381Sle		}
174129381Sle
175125699Spjd		stat = CLNT_CALL(rc->rc_client, proc, xargs, argsp,
176125699Spjd		    xresults, resultsp, utimeout);
177125699Spjd
178125699Spjd		if (stat == RPC_TIMEDOUT) {
179125699Spjd			/*
180125699Spjd			 * Check for async send misfeature for NLM
181125699Spjd			 * protocol.
182129381Sle			 */
183125699Spjd			if ((rc->rc_timeout.tv_sec == 0
184125699Spjd				&& rc->rc_timeout.tv_usec == 0)
185125699Spjd			    || (rc->rc_timeout.tv_sec == -1
186125699Spjd				&& utimeout.tv_sec == 0
187125699Spjd				&& utimeout.tv_usec == 0))
188125699Spjd				break;
189125699Spjd		}
190163872Spjd
191163872Spjd		if (stat == RPC_INTR)
192163872Spjd			break;
193163872Spjd
194163872Spjd		if (stat != RPC_SUCCESS) {
195163872Spjd			CLNT_DESTROY(rc->rc_client);
196163872Spjd			rc->rc_client = NULL;
197125699Spjd		}
198125699Spjd	} while (stat != RPC_SUCCESS);
199129381Sle
200125699Spjd	return (stat);
201125699Spjd}
202125714Spjd
203125714Spjdstatic void
204125714Spjdclnt_reconnect_geterr(CLIENT *cl, struct rpc_err *errp)
205129381Sle{
206125714Spjd	struct rc_data *rc = (struct rc_data *)cl->cl_private;
207129381Sle
208129381Sle	if (rc->rc_client)
209129381Sle		CLNT_GETERR(rc->rc_client, errp);
210129381Sle	else
211129381Sle		memset(errp, 0, sizeof(*errp));
212129381Sle}
213129381Sle
214129381Slestatic bool_t
215131689Sruclnt_reconnect_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr)
216131689Sru{
217131689Sru	struct rc_data *rc = (struct rc_data *)cl->cl_private;
218125699Spjd
219125699Spjd	return (CLNT_FREERES(rc->rc_client, xdr_res, res_ptr));
220131689Sru}
221125699Spjd
222125699Spjd/*ARGSUSED*/
223131689Srustatic void
224125699Spjdclnt_reconnect_abort(CLIENT *h)
225125699Spjd{
226125699Spjd}
227125699Spjd
228125699Spjdstatic bool_t
229125699Spjdclnt_reconnect_control(CLIENT *cl, u_int request, void *info)
230125699Spjd{
231125699Spjd	struct rc_data *rc = (struct rc_data *)cl->cl_private;
232125699Spjd
233125699Spjd	if (info == NULL) {
234125699Spjd		return (FALSE);
235125714Spjd	}
236169308Swkoszek	switch (request) {
237125714Spjd	case CLSET_TIMEOUT:
238125714Spjd		rc->rc_timeout = *(struct timeval *)info;
239125699Spjd		if (rc->rc_client)
240125699Spjd			CLNT_CONTROL(rc->rc_client, request, info);
241125699Spjd		break;
242125699Spjd
243125699Spjd	case CLGET_TIMEOUT:
244125699Spjd		*(struct timeval *)info = rc->rc_timeout;
245125699Spjd		break;
246125699Spjd
247125699Spjd	case CLSET_RETRY_TIMEOUT:
248125699Spjd		rc->rc_retry = *(struct timeval *)info;
249125699Spjd		if (rc->rc_client)
250125699Spjd			CLNT_CONTROL(rc->rc_client, request, info);
251125699Spjd		break;
252125699Spjd
253125699Spjd	case CLGET_RETRY_TIMEOUT:
254125699Spjd		*(struct timeval *)info = rc->rc_retry;
255125699Spjd		break;
256125699Spjd
257125699Spjd	case CLGET_VERS:
258125699Spjd		*(uint32_t *)info = rc->rc_vers;
259125699Spjd		break;
260125699Spjd
261125699Spjd	case CLSET_VERS:
262125699Spjd		rc->rc_vers = *(uint32_t *) info;
263131594Sru		if (rc->rc_client)
264125699Spjd			CLNT_CONTROL(rc->rc_client, CLSET_VERS, info);
265126861Spjd		break;
266125699Spjd
267125699Spjd	case CLGET_PROG:
268125699Spjd		*(uint32_t *)info = rc->rc_prog;
269125699Spjd		break;
270125699Spjd
271125699Spjd	case CLSET_PROG:
272125699Spjd		rc->rc_prog = *(uint32_t *) info;
273125699Spjd		if (rc->rc_client)
274125699Spjd			CLNT_CONTROL(rc->rc_client, request, info);
275125699Spjd		break;
276125699Spjd
277125699Spjd	case CLSET_WAITCHAN:
278		rc->rc_waitchan = *(const char **)info;
279		if (rc->rc_client)
280			CLNT_CONTROL(rc->rc_client, request, info);
281		break;
282
283	case CLGET_WAITCHAN:
284		*(const char **) info = rc->rc_waitchan;
285		break;
286
287	case CLSET_INTERRUPTIBLE:
288		rc->rc_intr = *(int *) info;
289		if (rc->rc_client)
290			CLNT_CONTROL(rc->rc_client, request, info);
291		break;
292
293	case CLGET_INTERRUPTIBLE:
294		*(int *) info = rc->rc_intr;
295		break;
296
297	default:
298		return (FALSE);
299	}
300
301	return (TRUE);
302}
303
304static void
305clnt_reconnect_destroy(CLIENT *cl)
306{
307	struct rc_data *rc = (struct rc_data *)cl->cl_private;
308
309	if (rc->rc_client)
310		CLNT_DESTROY(rc->rc_client);
311	mem_free(rc, sizeof(*rc));
312	mem_free(cl, sizeof (CLIENT));
313}
314