1 /* $NetBSD: clnt_vc.c,v 1.4 2000/07/14 08:40:42 fvdl Exp $ */
4 * Copyright (c) 2009, Sun Microsystems, Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * - Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 * - Neither the name of Sun Microsystems, Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
31 #if defined(LIBC_SCCS) && !defined(lint)
32 static char *sccsid2
= "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro";
33 static char *sccsid
= "@(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC";
34 static char sccsid3
[] = "@(#)clnt_vc.c 1.19 89/03/16 Copyr 1988 Sun Micro";
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
40 * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
42 * Copyright (C) 1984, Sun Microsystems, Inc.
44 * TCP based RPC supports 'batched calls'.
45 * A sequence of calls may be batched-up in a send buffer. The rpc call
46 * return immediately to the client even though the call was not necessarily
47 * sent. The batching occurs if the results' xdr routine is NULL (0) AND
48 * the rpc timeout value is zero (see clnt.h, rpc).
50 * Clients should NOT casually batch calls that in fact return results; that is,
51 * the server side should be aware that a call is batched and not produce any
52 * return message. Batched calls that produce many result messages can
53 * deadlock (netlock) the client and the server....
55 * Now go hang yourself.
59 * This code handles the special case of a NFSv4.n backchannel for
60 * callback RPCs. It is similar to clnt_vc.c, but uses the TCP
61 * connection provided by the client to the server.
64 #include <sys/param.h>
65 #include <sys/systm.h>
67 #include <sys/malloc.h>
69 #include <sys/mutex.h>
72 #include <sys/protosw.h>
73 #include <sys/socket.h>
74 #include <sys/socketvar.h>
76 #include <sys/syslog.h>
82 #include <netinet/tcp.h>
85 #include <rpc/rpc_com.h>
90 struct cmsgcred cmcred
;
93 static void clnt_bck_geterr(CLIENT
*, struct rpc_err
*);
94 static bool_t
clnt_bck_freeres(CLIENT
*, xdrproc_t
, void *);
95 static void clnt_bck_abort(CLIENT
*);
96 static bool_t
clnt_bck_control(CLIENT
*, u_int
, void *);
97 static void clnt_bck_close(CLIENT
*);
98 static void clnt_bck_destroy(CLIENT
*);
100 static struct clnt_ops clnt_bck_ops
= {
101 .cl_abort
= clnt_bck_abort
,
102 .cl_geterr
= clnt_bck_geterr
,
103 .cl_freeres
= clnt_bck_freeres
,
104 .cl_close
= clnt_bck_close
,
105 .cl_destroy
= clnt_bck_destroy
,
106 .cl_control
= clnt_bck_control
110 * Create a client handle for a connection.
111 * Default options are set, which the user can change using clnt_control()'s.
112 * This code handles the special case of an NFSv4.1 session backchannel
113 * call, which is sent on a TCP connection created against the server
118 struct socket
*so
, /* Server transport socket. */
119 const rpcprog_t prog
, /* program number */
120 const rpcvers_t vers
) /* version number */
122 CLIENT
*cl
; /* client handle */
123 struct ct_data
*ct
= NULL
; /* client handle */
125 struct rpc_msg call_msg
;
126 static uint32_t disrupt
;
130 disrupt
= (uint32_t)(long)so
;
132 cl
= (CLIENT
*)mem_alloc(sizeof (*cl
));
133 ct
= (struct ct_data
*)mem_alloc(sizeof (*ct
));
135 mtx_init(&ct
->ct_lock
, "ct->ct_lock", NULL
, MTX_DEF
);
137 ct
->ct_closing
= FALSE
;
138 ct
->ct_closed
= FALSE
;
139 ct
->ct_upcallrefs
= 0;
140 ct
->ct_closeit
= FALSE
;
143 * Set up private data struct
145 ct
->ct_wait
.tv_sec
= -1;
146 ct
->ct_wait
.tv_usec
= -1;
149 * Initialize call message
152 ct
->ct_xid
= ((uint32_t)++disrupt
) ^ __RPC_GETXID(&now
);
153 call_msg
.rm_xid
= ct
->ct_xid
;
154 call_msg
.rm_direction
= CALL
;
155 call_msg
.rm_call
.cb_rpcvers
= RPC_MSG_VERSION
;
156 call_msg
.rm_call
.cb_prog
= (uint32_t)prog
;
157 call_msg
.rm_call
.cb_vers
= (uint32_t)vers
;
160 * pre-serialize the static part of the call msg and stash it away
162 xdrmem_create(&xdrs
, ct
->ct_mcallc
, MCALL_MSG_SIZE
,
164 if (!xdr_callhdr(&xdrs
, &call_msg
))
166 ct
->ct_mpos
= XDR_GETPOS(&xdrs
);
168 ct
->ct_waitchan
= "rpcbck";
171 cl
->cl_ops
= &clnt_bck_ops
;
173 cl
->cl_auth
= authnone_create();
174 TAILQ_INIT(&ct
->ct_pending
);
178 mtx_destroy(&ct
->ct_lock
);
179 mem_free(ct
, sizeof (struct ct_data
));
180 mem_free(cl
, sizeof (CLIENT
));
186 CLIENT
*cl
, /* client handle */
187 struct rpc_callextra
*ext
, /* call metadata */
188 rpcproc_t proc
, /* procedure number */
189 struct mbuf
*args
, /* pointer to args */
190 struct mbuf
**resultsp
, /* pointer to results */
191 struct timeval utimeout
,
194 struct ct_data
*ct
= (struct ct_data
*) cl
->cl_private
;
196 struct rpc_err
*errp
;
199 struct rpc_msg reply_msg
;
201 int nrefreshes
= 2; /* number of times to refresh cred */
202 struct timeval timeout
;
204 struct mbuf
*mreq
= NULL
, *results
;
205 struct ct_request
*cr
;
208 cr
= malloc(sizeof(struct ct_request
), M_RPC
, M_WAITOK
);
210 mtx_lock(&ct
->ct_lock
);
212 if (ct
->ct_closing
|| ct
->ct_closed
) {
213 mtx_unlock(&ct
->ct_lock
);
215 return (RPC_CANTSEND
);
224 errp
= &ct
->ct_error
;
230 if (ct
->ct_wait
.tv_usec
== -1)
231 timeout
= utimeout
; /* use supplied timeout */
233 timeout
= ct
->ct_wait
; /* use default timeout */
236 mtx_assert(&ct
->ct_lock
, MA_OWNED
);
241 mtx_unlock(&ct
->ct_lock
);
244 * Leave space to pre-pend the record mark.
246 mreq
= m_gethdr(M_WAITOK
, MT_DATA
);
247 mreq
->m_data
+= sizeof(uint32_t);
248 KASSERT(ct
->ct_mpos
+ sizeof(uint32_t) <= MHLEN
,
249 ("RPC header too big"));
250 bcopy(ct
->ct_mcallc
, mreq
->m_data
, ct
->ct_mpos
);
251 mreq
->m_len
= ct
->ct_mpos
;
254 * The XID is the first thing in the request.
256 *mtod(mreq
, uint32_t *) = htonl(xid
);
258 xdrmbuf_create(&xdrs
, mreq
, XDR_ENCODE
);
260 errp
->re_status
= stat
= RPC_SUCCESS
;
262 if ((!XDR_PUTINT32(&xdrs
, &proc
)) ||
263 (!AUTH_MARSHALL(auth
, xid
, &xdrs
,
264 m_copym(args
, 0, M_COPYALL
, M_WAITOK
)))) {
265 errp
->re_status
= stat
= RPC_CANTENCODEARGS
;
266 mtx_lock(&ct
->ct_lock
);
269 mreq
->m_pkthdr
.len
= m_length(mreq
, NULL
);
272 * Prepend a record marker containing the packet length.
274 M_PREPEND(mreq
, sizeof(uint32_t), M_WAITOK
);
275 *mtod(mreq
, uint32_t *) =
276 htonl(0x80000000 | (mreq
->m_pkthdr
.len
- sizeof(uint32_t)));
279 mtx_lock(&ct
->ct_lock
);
281 * Check to see if the client end has already started to close down
282 * the connection. The svc code will have set ct_error.re_status
283 * to RPC_CANTRECV if this is the case.
284 * If the client starts to close down the connection after this
285 * point, it will be detected later when cr_error is checked,
286 * since the request is in the ct_pending queue.
288 if (ct
->ct_error
.re_status
== RPC_CANTRECV
) {
289 if (errp
!= &ct
->ct_error
) {
290 errp
->re_errno
= ct
->ct_error
.re_errno
;
291 errp
->re_status
= RPC_CANTRECV
;
296 TAILQ_INSERT_TAIL(&ct
->ct_pending
, cr
, cr_link
);
297 mtx_unlock(&ct
->ct_lock
);
300 * sosend consumes mreq.
302 sx_xlock(&xprt
->xp_lock
);
303 error
= sosend(xprt
->xp_socket
, NULL
, NULL
, mreq
, NULL
, 0, curthread
);
304 if (error
!= 0) printf("sosend=%d\n", error
);
306 if (error
== EMSGSIZE
) {
307 printf("emsgsize\n");
308 SOCKBUF_LOCK(&xprt
->xp_socket
->so_snd
);
309 sbwait(&xprt
->xp_socket
->so_snd
);
310 SOCKBUF_UNLOCK(&xprt
->xp_socket
->so_snd
);
311 sx_xunlock(&xprt
->xp_lock
);
312 AUTH_VALIDATE(auth
, xid
, NULL
, NULL
);
313 mtx_lock(&ct
->ct_lock
);
314 TAILQ_REMOVE(&ct
->ct_pending
, cr
, cr_link
);
317 sx_xunlock(&xprt
->xp_lock
);
319 reply_msg
.acpted_rply
.ar_verf
.oa_flavor
= AUTH_NULL
;
320 reply_msg
.acpted_rply
.ar_verf
.oa_base
= cr
->cr_verf
;
321 reply_msg
.acpted_rply
.ar_verf
.oa_length
= 0;
322 reply_msg
.acpted_rply
.ar_results
.where
= NULL
;
323 reply_msg
.acpted_rply
.ar_results
.proc
= (xdrproc_t
)xdr_void
;
325 mtx_lock(&ct
->ct_lock
);
327 TAILQ_REMOVE(&ct
->ct_pending
, cr
, cr_link
);
328 errp
->re_errno
= error
;
329 errp
->re_status
= stat
= RPC_CANTSEND
;
334 * Check to see if we got an upcall while waiting for the
335 * lock. In both these cases, the request has been removed
336 * from ct->ct_pending.
339 TAILQ_REMOVE(&ct
->ct_pending
, cr
, cr_link
);
340 errp
->re_errno
= cr
->cr_error
;
341 errp
->re_status
= stat
= RPC_CANTRECV
;
345 TAILQ_REMOVE(&ct
->ct_pending
, cr
, cr_link
);
350 * Hack to provide rpc-based message passing
352 if (timeout
.tv_sec
== 0 && timeout
.tv_usec
== 0) {
353 TAILQ_REMOVE(&ct
->ct_pending
, cr
, cr_link
);
354 errp
->re_status
= stat
= RPC_TIMEDOUT
;
358 error
= msleep(cr
, &ct
->ct_lock
, ct
->ct_waitflag
, ct
->ct_waitchan
,
361 TAILQ_REMOVE(&ct
->ct_pending
, cr
, cr_link
);
365 * The sleep returned an error so our request is still
366 * on the list. Turn the error code into an
367 * appropriate client status.
369 errp
->re_errno
= error
;
380 errp
->re_status
= stat
;
384 * We were woken up by the svc thread. If the
385 * upcall had a receive error, report that,
386 * otherwise we have a reply.
389 errp
->re_errno
= cr
->cr_error
;
390 errp
->re_status
= stat
= RPC_CANTRECV
;
397 * Now decode and validate the response. We need to drop the
398 * lock since xdr_replymsg may end up sleeping in malloc.
400 mtx_unlock(&ct
->ct_lock
);
402 if (ext
&& ext
->rc_feedback
)
403 ext
->rc_feedback(FEEDBACK_OK
, proc
, ext
->rc_feedback_arg
);
405 xdrmbuf_create(&xdrs
, cr
->cr_mrep
, XDR_DECODE
);
406 ok
= xdr_replymsg(&xdrs
, &reply_msg
);
410 if ((reply_msg
.rm_reply
.rp_stat
== MSG_ACCEPTED
) &&
411 (reply_msg
.acpted_rply
.ar_stat
== SUCCESS
))
412 errp
->re_status
= stat
= RPC_SUCCESS
;
414 stat
= _seterr_reply(&reply_msg
, errp
);
416 if (stat
== RPC_SUCCESS
) {
417 results
= xdrmbuf_getall(&xdrs
);
418 if (!AUTH_VALIDATE(auth
, xid
,
419 &reply_msg
.acpted_rply
.ar_verf
, &results
)) {
420 errp
->re_status
= stat
= RPC_AUTHERROR
;
421 errp
->re_why
= AUTH_INVALIDRESP
;
424 ("auth validated but no result"));
427 } /* end successful completion */
429 * If unsuccessful AND error is an authentication error
430 * then refresh credentials and try again, else break
432 else if (stat
== RPC_AUTHERROR
)
433 /* maybe our credentials need to be refreshed ... */
434 if (nrefreshes
> 0 && AUTH_REFRESH(auth
, &reply_msg
)) {
437 mtx_lock(&ct
->ct_lock
);
440 /* end of unsuccessful completion */
441 /* end of valid reply message */
443 errp
->re_status
= stat
= RPC_CANTDECODERES
;
445 mtx_lock(&ct
->ct_lock
);
447 mtx_assert(&ct
->ct_lock
, MA_OWNED
);
449 KASSERT(stat
!= RPC_SUCCESS
|| *resultsp
,
450 ("RPC_SUCCESS without reply"));
454 if (cr
->cr_mrep
!= NULL
)
455 m_freem(cr
->cr_mrep
);
461 mtx_unlock(&ct
->ct_lock
);
463 if (auth
&& stat
!= RPC_SUCCESS
)
464 AUTH_VALIDATE(auth
, xid
, NULL
, NULL
);
472 clnt_bck_geterr(CLIENT
*cl
, struct rpc_err
*errp
)
474 struct ct_data
*ct
= (struct ct_data
*) cl
->cl_private
;
476 *errp
= ct
->ct_error
;
480 clnt_bck_freeres(CLIENT
*cl
, xdrproc_t xdr_res
, void *res_ptr
)
485 xdrs
.x_op
= XDR_FREE
;
486 dummy
= (*xdr_res
)(&xdrs
, res_ptr
);
493 clnt_bck_abort(CLIENT
*cl
)
498 clnt_bck_control(CLIENT
*cl
, u_int request
, void *info
)
505 clnt_bck_close(CLIENT
*cl
)
507 struct ct_data
*ct
= (struct ct_data
*) cl
->cl_private
;
509 mtx_lock(&ct
->ct_lock
);
512 mtx_unlock(&ct
->ct_lock
);
516 if (ct
->ct_closing
) {
517 while (ct
->ct_closing
)
518 msleep(ct
, &ct
->ct_lock
, 0, "rpcclose", 0);
519 KASSERT(ct
->ct_closed
, ("client should be closed"));
520 mtx_unlock(&ct
->ct_lock
);
524 ct
->ct_closing
= FALSE
;
525 ct
->ct_closed
= TRUE
;
526 mtx_unlock(&ct
->ct_lock
);
531 clnt_bck_destroy(CLIENT
*cl
)
533 struct ct_data
*ct
= (struct ct_data
*) cl
->cl_private
;
537 mtx_destroy(&ct
->ct_lock
);
538 mem_free(ct
, sizeof(struct ct_data
));
539 if (cl
->cl_netid
&& cl
->cl_netid
[0])
540 mem_free(cl
->cl_netid
, strlen(cl
->cl_netid
) +1);
541 if (cl
->cl_tp
&& cl
->cl_tp
[0])
542 mem_free(cl
->cl_tp
, strlen(cl
->cl_tp
) +1);
543 mem_free(cl
, sizeof(CLIENT
));
547 * This call is done by the svc code when a backchannel RPC reply is
551 clnt_bck_svccall(void *arg
, struct mbuf
*mrep
, uint32_t xid
)
553 struct ct_data
*ct
= (struct ct_data
*)arg
;
554 struct ct_request
*cr
;
557 mtx_lock(&ct
->ct_lock
);
560 * See if we can match this reply to a request.
563 TAILQ_FOREACH(cr
, &ct
->ct_pending
, cr_link
) {
564 if (cr
->cr_xid
== xid
) {
566 * This one matches. We leave the reply mbuf list in
567 * cr->cr_mrep. Set the XID to zero so that we will
568 * ignore any duplicated replies.
580 if (ct
->ct_upcallrefs
< 0)
581 panic("rpcvc svccall refcnt");
582 if (ct
->ct_upcallrefs
== 0)
583 wakeup(&ct
->ct_upcallrefs
);
584 mtx_unlock(&ct
->ct_lock
);