4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * clnt_doors.c, Client side for doors IPC based RPC.
37 #include <sys/types.h>
38 #include <sys/kstat.h>
45 #include <rpc/svc_mt.h>
50 extern bool_t
xdr_opaque_auth(XDR
*, struct opaque_auth
*);
52 static struct clnt_ops
*clnt_door_ops();
54 extern int __rpc_default_door_buf_size
;
55 extern int __rpc_min_door_buf_size
;
58 * Private data kept per client handle
61 int cu_fd
; /* door fd */
62 bool_t cu_closeit
; /* close it on destroy */
63 struct rpc_err cu_error
;
65 uint_t cu_sendsz
; /* send size */
66 char cu_header
[32]; /* precreated header */
70 * Door IPC based client creation routine.
72 * NB: The rpch->cl_auth is initialized to null authentication.
73 * Caller may wish to set this something more useful.
75 * sendsz is the maximum allowable packet size that can be sent.
76 * 0 will cause default to be used.
79 clnt_door_create(const rpcprog_t program
, const rpcvers_t version
,
82 CLIENT
*cl
= NULL
; /* client handle */
83 struct cu_data
*cu
= NULL
; /* private data */
84 struct rpc_msg call_msg
;
87 struct door_info info
;
92 (void) sprintf(rendezvous
, RPC_DOOR_RENDEZVOUS
, (int)program
,
94 if ((did
= open(rendezvous
, O_RDONLY
, 0)) < 0) {
95 rpc_createerr
.cf_stat
= RPC_PROGNOTREGISTERED
;
96 rpc_createerr
.cf_error
.re_errno
= errno
;
97 rpc_createerr
.cf_error
.re_terrno
= 0;
101 if (door_info(did
, &info
) < 0 || (info
.di_attributes
& DOOR_REVOKED
)) {
103 rpc_createerr
.cf_stat
= RPC_PROGNOTREGISTERED
;
104 rpc_createerr
.cf_error
.re_errno
= errno
;
105 rpc_createerr
.cf_error
.re_terrno
= 0;
110 * Determine send size
112 if (sendsz
< __rpc_min_door_buf_size
)
113 ssz
= __rpc_default_door_buf_size
;
117 if ((cl
= malloc(sizeof (CLIENT
))) == NULL
||
118 (cu
= malloc(sizeof (*cu
))) == NULL
) {
119 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
120 rpc_createerr
.cf_error
.re_errno
= errno
;
125 * Precreate RPC header for performance reasons.
127 (void) gettimeofday(&now
, NULL
);
128 call_msg
.rm_xid
= getpid() ^ now
.tv_sec
^ now
.tv_usec
;
129 call_msg
.rm_call
.cb_prog
= program
;
130 call_msg
.rm_call
.cb_vers
= version
;
131 xdrmem_create(&xdrs
, cu
->cu_header
, sizeof (cu
->cu_header
), XDR_ENCODE
);
132 if (!xdr_callhdr(&xdrs
, &call_msg
)) {
133 rpc_createerr
.cf_stat
= RPC_CANTENCODEARGS
;
134 rpc_createerr
.cf_error
.re_errno
= 0;
137 cu
->cu_xdrpos
= XDR_GETPOS(&xdrs
);
141 cu
->cu_closeit
= TRUE
;
142 cl
->cl_ops
= clnt_door_ops();
143 cl
->cl_private
= (caddr_t
)cu
;
144 cl
->cl_auth
= authnone_create();
145 cl
->cl_tp
= strdup(rendezvous
);
146 if (cl
->cl_tp
== NULL
) {
147 syslog(LOG_ERR
, "clnt_door_create: strdup failed");
148 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
149 rpc_createerr
.cf_error
.re_errno
= errno
;
152 cl
->cl_netid
= strdup("door");
153 if (cl
->cl_netid
== NULL
) {
154 syslog(LOG_ERR
, "clnt_door_create: strdup failed");
156 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
157 rpc_createerr
.cf_error
.re_errno
= errno
;
162 rpc_createerr
.cf_error
.re_terrno
= 0;
172 static enum clnt_stat
173 clnt_door_call(CLIENT
*cl
, rpcproc_t proc
, xdrproc_t xargs
, caddr_t argsp
,
174 xdrproc_t xresults
, caddr_t resultsp
, struct timeval utimeout
)
176 /* LINTED pointer alignment */
177 struct cu_data
*cu
= (struct cu_data
*)cl
->cl_private
;
181 struct rpc_msg reply_msg
;
182 bool_t need_to_unmap
;
184 int nrefreshes
= 2; /* number of times to refresh cred */
186 rpc_callerr
.re_errno
= 0;
187 rpc_callerr
.re_terrno
= 0;
189 if ((params
.rbuf
= alloca(cu
->cu_sendsz
)) == NULL
) {
190 rpc_callerr
.re_terrno
= 0;
191 rpc_callerr
.re_errno
= errno
;
192 return (rpc_callerr
.re_status
= RPC_SYSTEMERROR
);
194 outbuf_ref
= params
.rbuf
;
195 params
.rsize
= cu
->cu_sendsz
;
196 if ((params
.data_ptr
= alloca(cu
->cu_sendsz
)) == NULL
) {
197 rpc_callerr
.re_terrno
= 0;
198 rpc_callerr
.re_errno
= errno
;
199 return (rpc_callerr
.re_status
= RPC_SYSTEMERROR
);
203 xdrmem_create(&xdrs
, params
.data_ptr
, cu
->cu_sendsz
, XDR_ENCODE
);
204 /* Increment XID (not really needed for RPC over doors...) */
205 /* LINTED pointer alignment */
206 xid
= atomic_inc_uint_nv((uint32_t *)cu
->cu_header
);
207 (void) memcpy(params
.data_ptr
, cu
->cu_header
, cu
->cu_xdrpos
);
208 /* LINTED pointer alignment */
209 *(uint32_t *)params
.data_ptr
= xid
;
210 XDR_SETPOS(&xdrs
, cu
->cu_xdrpos
);
212 if ((!XDR_PUTINT32(&xdrs
, (int32_t *)&proc
)) ||
213 (!AUTH_MARSHALL(cl
->cl_auth
, &xdrs
)) ||
214 (!(*xargs
)(&xdrs
, argsp
))) {
215 return (rpc_callerr
.re_status
= RPC_CANTENCODEARGS
);
217 params
.data_size
= (int)XDR_GETPOS(&xdrs
);
219 params
.desc_ptr
= NULL
;
221 if (door_call(cu
->cu_fd
, ¶ms
) < 0) {
222 rpc_callerr
.re_errno
= errno
;
223 return (rpc_callerr
.re_status
= RPC_CANTSEND
);
226 if (params
.rbuf
== NULL
|| params
.rsize
== 0) {
227 return (rpc_callerr
.re_status
= RPC_FAILED
);
229 need_to_unmap
= (params
.rbuf
!= outbuf_ref
);
231 /* LINTED pointer alignment */
232 if (*(uint32_t *)params
.rbuf
!= xid
) {
233 rpc_callerr
.re_status
= RPC_CANTDECODERES
;
237 xdrmem_create(&xdrs
, params
.rbuf
, params
.rsize
, XDR_DECODE
);
238 reply_msg
.acpted_rply
.ar_verf
= _null_auth
;
239 reply_msg
.acpted_rply
.ar_results
.where
= resultsp
;
240 reply_msg
.acpted_rply
.ar_results
.proc
= xresults
;
242 if (xdr_replymsg(&xdrs
, &reply_msg
)) {
243 if (reply_msg
.rm_reply
.rp_stat
== MSG_ACCEPTED
&&
244 reply_msg
.acpted_rply
.ar_stat
== SUCCESS
)
245 rpc_callerr
.re_status
= RPC_SUCCESS
;
247 __seterr_reply(&reply_msg
, &rpc_callerr
);
249 if (rpc_callerr
.re_status
== RPC_SUCCESS
) {
250 if (!AUTH_VALIDATE(cl
->cl_auth
,
251 &reply_msg
.acpted_rply
.ar_verf
)) {
252 rpc_callerr
.re_status
= RPC_AUTHERROR
;
253 rpc_callerr
.re_why
= AUTH_INVALIDRESP
;
255 if (reply_msg
.acpted_rply
.ar_verf
.oa_base
!= NULL
) {
256 xdrs
.x_op
= XDR_FREE
;
257 (void) xdr_opaque_auth(&xdrs
,
258 &(reply_msg
.acpted_rply
.ar_verf
));
262 * If unsuccesful AND error is an authentication error
263 * then refresh credentials and try again, else break
265 else if (rpc_callerr
.re_status
== RPC_AUTHERROR
) {
267 * maybe our credentials need to be refreshed ...
270 AUTH_REFRESH(cl
->cl_auth
, &reply_msg
)) {
272 (void) munmap(params
.rbuf
,
277 * We are setting rpc_callerr here given that
278 * libnsl is not reentrant thereby
279 * reinitializing the TSD. If not set here then
280 * success could be returned even though refresh
283 rpc_callerr
.re_status
= RPC_AUTHERROR
;
286 rpc_callerr
.re_status
= RPC_CANTDECODERES
;
290 (void) munmap(params
.rbuf
, params
.rsize
);
291 return (rpc_callerr
.re_status
);
295 static enum clnt_stat
296 clnt_door_send(CLIENT
*cl
, rpcproc_t proc
, xdrproc_t xargs
, caddr_t argsp
)
298 /* send() call not supported on doors */
300 rpc_callerr
.re_errno
= ENOTSUP
;
301 rpc_callerr
.re_terrno
= 0;
303 return (rpc_callerr
.re_status
= RPC_FAILED
);
307 clnt_door_geterr(CLIENT
*cl
, struct rpc_err
*errp
)
309 /* LINTED pointer alignment */
310 struct cu_data
*cu
= (struct cu_data
*)cl
->cl_private
;
317 clnt_door_freeres(CLIENT
*cl
, xdrproc_t xdr_res
, caddr_t res_ptr
)
321 (void) memset(&xdrs
, 0, sizeof (xdrs
));
322 xdrs
.x_op
= XDR_FREE
;
323 return ((*xdr_res
)(&xdrs
, res_ptr
));
327 clnt_door_abort(CLIENT
*cl
)
333 clnt_door_control(CLIENT
*cl
, int request
, char *info
)
335 /* LINTED pointer alignment */
336 struct cu_data
*cu
= (struct cu_data
*)cl
->cl_private
;
340 cu
->cu_closeit
= TRUE
;
343 case CLSET_FD_NCLOSE
:
344 cu
->cu_closeit
= FALSE
;
348 /* for other requests which use info */
354 /* LINTED pointer alignment */
355 *(int *)info
= cu
->cu_fd
;
360 * use the knowledge that xid is the
361 * first element in the call structure *.
362 * This will get the xid of the PREVIOUS call
364 /* LINTED pointer alignment */
365 *(uint32_t *)info
= ntohl(*(uint32_t *)cu
->cu_header
);
369 /* This will set the xid of the NEXT call */
370 /* LINTED pointer alignment */
371 *(uint32_t *)cu
->cu_header
= htonl(*(uint32_t *)info
- 1);
372 /* decrement by 1 as clnt_door_call() increments once */
377 * This RELIES on the information that, in the call body,
378 * the version number field is the fifth field from the
379 * begining of the RPC header. MUST be changed if the
380 * call_struct is changed
382 /* LINTED pointer alignment */
383 *(uint32_t *)info
= ntohl(*(uint32_t *)(cu
->cu_header
+
384 4 * BYTES_PER_XDR_UNIT
));
388 /* LINTED pointer alignment */
389 *(uint32_t *)(cu
->cu_header
+ 4 * BYTES_PER_XDR_UNIT
) =
390 /* LINTED pointer alignment */
391 htonl(*(uint32_t *)info
);
396 * This RELIES on the information that, in the call body,
397 * the program number field is the fourth field from the
398 * begining of the RPC header. MUST be changed if the
399 * call_struct is changed
401 /* LINTED pointer alignment */
402 *(uint32_t *)info
= ntohl(*(uint32_t *)(cu
->cu_header
+
403 3 * BYTES_PER_XDR_UNIT
));
407 /* LINTED pointer alignment */
408 *(uint32_t *)(cu
->cu_header
+ 3 * BYTES_PER_XDR_UNIT
) =
409 /* LINTED pointer alignment */
410 htonl(*(uint32_t *)info
);
420 clnt_door_destroy(CLIENT
*cl
)
422 /* LINTED pointer alignment */
423 struct cu_data
*cu
= (struct cu_data
*)cl
->cl_private
;
424 int cu_fd
= cu
->cu_fd
;
429 if (cl
->cl_netid
&& cl
->cl_netid
[0])
431 if (cl
->cl_tp
&& cl
->cl_tp
[0])
436 static struct clnt_ops
*
439 static struct clnt_ops ops
;
440 extern mutex_t ops_lock
;
442 sig_mutex_lock(&ops_lock
);
443 if (ops
.cl_call
== NULL
) {
444 ops
.cl_call
= clnt_door_call
;
445 ops
.cl_send
= clnt_door_send
;
446 ops
.cl_abort
= clnt_door_abort
;
447 ops
.cl_geterr
= clnt_door_geterr
;
448 ops
.cl_freeres
= clnt_door_freeres
;
449 ops
.cl_destroy
= clnt_door_destroy
;
450 ops
.cl_control
= clnt_door_control
;
452 sig_mutex_unlock(&ops_lock
);
457 _update_did(CLIENT
*cl
, int vers
)
459 /* LINTED pointer alignment */
460 struct cu_data
*cu
= (struct cu_data
*)cl
->cl_private
;
465 (void) close(cu
->cu_fd
);
466 /* Make sure that the right door id is used in door_call. */
467 clnt_control(cl
, CLGET_PROG
, (void *)&prog
);
468 (void) sprintf(rendezvous
, RPC_DOOR_RENDEZVOUS
, (int)prog
, vers
);
469 if ((cu
->cu_fd
= open(rendezvous
, O_RDONLY
, 0)) < 0) {
470 rpc_createerr
.cf_stat
= RPC_PROGNOTREGISTERED
;
471 rpc_createerr
.cf_error
.re_errno
= errno
;
472 rpc_createerr
.cf_error
.re_terrno
= 0;
476 cl
->cl_tp
= strdup(rendezvous
);
477 if (cl
->cl_tp
== NULL
) {
478 syslog(LOG_ERR
, "_update_did: strdup failed");
479 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
480 rpc_createerr
.cf_error
.re_errno
= errno
;
481 rpc_createerr
.cf_error
.re_terrno
= 0;