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 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
30 * Portions of this source code were derived from Berkeley
31 * 4.3 BSD under license from the Regents of the University of
35 #pragma ident "%Z%%M% %I% %E% SMI"
40 * The backward compatibility routines for the earlier implementation
41 * of RPC, where the only transports supported were tcp/ip and udp/ip.
42 * Based on berkeley socket abstraction, now implemented on the top
49 #include <sys/types.h>
51 #include <rpc/clnt_soc.h>
52 #include <netinet/in.h>
53 #include <sys/socket.h>
57 #include <sys/syslog.h>
58 #include <rpc/pmap_clnt.h>
59 #include <rpc/pmap_prot.h>
60 #include <rpc/nettype.h>
66 int __rpc_bindresvport(int, struct sockaddr_in
*, int *, int);
67 int __rpc_bindresvport_ipv6(int, struct sockaddr
*, int *, int, char *);
68 void get_myaddress_ipv6(char *, struct sockaddr
*);
70 extern mutex_t rpcsoc_lock
;
73 * A common clnt create routine
76 clnt_com_create(struct sockaddr_in
*raddr
, rpcprog_t prog
, rpcvers_t vers
,
77 int *sockp
, uint_t sendsz
, uint_t recvsz
, char *tp
)
83 struct netconfig
*nconf
;
85 struct netbuf bindaddr
;
88 (void) mutex_lock(&rpcsoc_lock
);
89 if ((nconf
= __rpc_getconfip(tp
)) == NULL
) {
90 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
91 (void) mutex_unlock(&rpcsoc_lock
);
94 if (fd
== RPC_ANYSOCK
) {
95 fd
= t_open(nconf
->nc_device
, O_RDWR
, &tinfo
);
101 if (t_getinfo(fd
, &tinfo
) == -1)
105 if (raddr
->sin_port
== 0) {
109 /* pmap_getport is recursive */
110 (void) mutex_unlock(&rpcsoc_lock
);
111 proto
= strcmp(tp
, "udp") == 0 ? IPPROTO_UDP
: IPPROTO_TCP
;
112 sport
= pmap_getport(raddr
, prog
, vers
, proto
);
117 raddr
->sin_port
= htons(sport
);
118 /* pmap_getport is recursive */
119 (void) mutex_lock(&rpcsoc_lock
);
122 /* Transform sockaddr_in to netbuf */
123 bindaddr
.maxlen
= bindaddr
.len
= __rpc_get_a_size(tinfo
.addr
);
124 bindaddr
.buf
= (char *)raddr
;
126 (void) __rpc_bindresvport(fd
, NULL
, &port
, 0);
127 cl
= clnt_tli_create(fd
, nconf
, &bindaddr
, prog
, vers
,
130 if (madefd
== TRUE
) {
132 * The fd should be closed while destroying the handle.
134 (void) CLNT_CONTROL(cl
, CLSET_FD_CLOSE
, NULL
);
137 (void) freenetconfigent(nconf
);
138 (void) mutex_unlock(&rpcsoc_lock
);
144 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
145 rpc_createerr
.cf_error
.re_errno
= errno
;
146 rpc_createerr
.cf_error
.re_terrno
= t_errno
;
148 err
: if (madefd
== TRUE
)
150 (void) freenetconfigent(nconf
);
152 (void) mutex_unlock(&rpcsoc_lock
);
157 clntudp_bufcreate(struct sockaddr_in
*raddr
, rpcprog_t prog
, rpcvers_t vers
,
158 struct timeval wait
, int *sockp
, uint_t sendsz
, uint_t recvsz
)
162 cl
= clnt_com_create(raddr
, prog
, vers
, sockp
, sendsz
, recvsz
, "udp");
165 (void) CLNT_CONTROL(cl
, CLSET_RETRY_TIMEOUT
, (char *)&wait
);
170 clntudp_create(struct sockaddr_in
*raddr
, rpcprog_t program
, rpcvers_t version
,
171 struct timeval wait
, int *sockp
)
173 return (clntudp_bufcreate(raddr
, program
, version
, wait
, sockp
,
174 UDPMSGSIZE
, UDPMSGSIZE
));
178 clnttcp_create(struct sockaddr_in
*raddr
, rpcprog_t prog
, rpcvers_t vers
,
179 int *sockp
, uint_t sendsz
, uint_t recvsz
)
181 return (clnt_com_create(raddr
, prog
, vers
, sockp
, sendsz
,
186 clntraw_create(rpcprog_t prog
, rpcvers_t vers
)
188 return (clnt_raw_create(prog
, vers
));
192 * A common server create routine
195 svc_com_create(int fd
, uint_t sendsize
, uint_t recvsize
, char *netid
)
197 struct netconfig
*nconf
;
203 if ((nconf
= __rpc_getconfip(netid
)) == NULL
) {
204 (void) syslog(LOG_ERR
, "Could not get %s transport", netid
);
207 if (fd
== RPC_ANYSOCK
) {
208 fd
= t_open(nconf
->nc_device
, O_RDWR
, NULL
);
212 __tli_sys_strerror(errorstr
, sizeof (errorstr
),
214 (void) syslog(LOG_ERR
,
215 "svc%s_create: could not open connection : %s", netid
,
217 (void) freenetconfigent(nconf
);
223 res
= __rpc_bindresvport(fd
, NULL
, &port
, 8);
224 svc
= svc_tli_create(fd
, nconf
, NULL
,
226 (void) freenetconfigent(nconf
);
233 /* LINTED pointer cast */
234 port
= (((struct sockaddr_in
*)svc
->xp_ltaddr
.buf
)->sin_port
);
235 svc
->xp_port
= ntohs(port
);
240 svctcp_create(int fd
, uint_t sendsize
, uint_t recvsize
)
242 return (svc_com_create(fd
, sendsize
, recvsize
, "tcp"));
246 svcudp_bufcreate(int fd
, uint_t sendsz
, uint_t recvsz
)
248 return (svc_com_create(fd
, sendsz
, recvsz
, "udp"));
252 svcfd_create(int fd
, uint_t sendsize
, uint_t recvsize
)
254 return (svc_fd_create(fd
, sendsize
, recvsize
));
259 svcudp_create(int fd
)
261 return (svc_com_create(fd
, UDPMSGSIZE
, UDPMSGSIZE
, "udp"));
267 return (svc_raw_create());
271 * Bind a fd to a privileged IP port.
272 * This is slightly different from the code in netdir_options
273 * because it has a different interface - main thing is that it
274 * needs to know its own address. We also wanted to set the qlen.
275 * t_getname() can be used for those purposes and perhaps job can be done.
278 __rpc_bindresvport_ipv6(int fd
, struct sockaddr
*sin
, int *portp
, int qlen
,
282 static in_port_t port
, *sinport
;
283 struct sockaddr_in6 myaddr
;
285 struct t_bind tbindstr
, *tres
;
287 extern mutex_t portnum_lock
;
289 /* VARIABLES PROTECTED BY portnum_lock: port */
291 #define STARTPORT 600
292 #define ENDPORT (IPPORT_RESERVED - 1)
293 #define NPORTS (ENDPORT - STARTPORT + 1)
295 if (sin
== 0 && fmly
== 0) {
303 if ((i
= t_getstate(fd
)) != T_UNBND
) {
304 if (t_errno
== TBADF
)
311 sin
= (struct sockaddr
*)&myaddr
;
312 get_myaddress_ipv6(fmly
, sin
);
314 if (sin
->sa_family
== AF_INET
) {
315 /* LINTED pointer cast */
316 sinport
= &((struct sockaddr_in
*)sin
)->sin_port
;
317 } else if (sin
->sa_family
== AF_INET6
) {
318 /* LINTED pointer cast */
319 sinport
= &((struct sockaddr_in6
*)sin
)->sin6_port
;
321 errno
= EPFNOSUPPORT
;
325 /* Transform sockaddr to netbuf */
326 if (t_getinfo(fd
, &tinfo
) == -1) {
329 /* LINTED pointer cast */
330 tres
= (struct t_bind
*)t_alloc(fd
, T_BIND
, T_ADDR
);
334 tbindstr
.qlen
= qlen
;
335 tbindstr
.addr
.buf
= (char *)sin
;
336 tbindstr
.addr
.len
= tbindstr
.addr
.maxlen
= __rpc_get_a_size(tinfo
.addr
);
337 /* LINTED pointer cast */
338 sin
= (struct sockaddr
*)tbindstr
.addr
.buf
;
341 (void) mutex_lock(&portnum_lock
);
343 port
= (getpid() % NPORTS
) + STARTPORT
;
344 for (i
= 0; i
< NPORTS
; i
++) {
345 *sinport
= htons(port
++);
348 res
= t_bind(fd
, &tbindstr
, tres
);
350 if ((tbindstr
.addr
.len
== tres
->addr
.len
) &&
351 (memcmp(tbindstr
.addr
.buf
, tres
->addr
.buf
,
352 (int)tres
->addr
.len
) == 0))
356 } else if (t_errno
!= TSYSERR
|| errno
!= EADDRINUSE
)
359 (void) mutex_unlock(&portnum_lock
);
361 if ((portp
!= NULL
) && (res
== 0))
363 (void) t_free((char *)tres
, T_BIND
);
368 __rpc_bindresvport(int fd
, struct sockaddr_in
*sin
, int *portp
, int qlen
)
370 return (__rpc_bindresvport_ipv6(fd
, (struct sockaddr
*)sin
, portp
,
375 * Get clients IP address.
376 * don't use gethostbyname, which would invoke yellow pages
377 * Remains only for backward compatibility reasons.
378 * Used mainly by the portmapper so that it can register
379 * with itself. Also used by pmap*() routines
382 get_myaddress_ipv6(char *fmly
, struct sockaddr
*addr
)
384 if (fmly
!= 0 && strcmp(fmly
, NC_INET6
) == 0) {
385 /* LINTED pointer cast */
386 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)addr
;
387 (void) memset(sin6
, 0, sizeof (*sin6
));
388 sin6
->sin6_family
= AF_INET6
;
389 sin6
->sin6_port
= htons(PMAPPORT
);
390 if (__can_use_af(AF_INET6
)) {
391 sin6
->sin6_addr
= in6addr_any
;
394 in4
.s_addr
= INADDR_ANY
;
395 IN6_INADDR_TO_V4MAPPED(&in4
, &sin6
->sin6_addr
);
398 /* LINTED pointer cast */
399 struct sockaddr_in
*sin
= (struct sockaddr_in
*)addr
;
400 (void) memset(sin
, 0, sizeof (*sin
));
401 sin
->sin_family
= AF_INET
;
402 sin
->sin_port
= htons(PMAPPORT
);
403 sin
->sin_addr
.s_addr
= INADDR_ANY
;
408 get_myaddress(struct sockaddr_in
*addr
)
410 get_myaddress_ipv6(0, (struct sockaddr
*)addr
);
414 * Get port used by specified service on specified host.
415 * Exists for source compatibility only.
416 * Obsoleted by rpcb_getaddr().
419 getrpcport(char *host
, rpcprog_t prognum
, rpcvers_t versnum
,
422 struct sockaddr_in addr
;
425 if ((hp
= gethostbyname(host
)) == NULL
)
427 (void) memcpy(&addr
.sin_addr
, hp
->h_addr
, hp
->h_length
);
428 addr
.sin_family
= AF_INET
;
430 return (pmap_getport(&addr
, prognum
, versnum
, proto
));
434 * For connectionless "udp" transport. Obsoleted by rpc_call().
437 callrpc(char *host
, rpcprog_t prognum
, rpcvers_t versnum
, rpcproc_t procnum
,
438 xdrproc_t inproc
, char *in
, xdrproc_t outproc
, char *out
)
440 return ((int)rpc_call(host
, prognum
, versnum
, procnum
, inproc
,
441 in
, outproc
, out
, "udp"));
445 * For connectionless kind of transport. Obsoleted by rpc_reg()
448 registerrpc(rpcprog_t prognum
, rpcvers_t versnum
, rpcproc_t procnum
,
449 char *(*progname
)(), xdrproc_t inproc
, xdrproc_t outproc
)
451 return (rpc_reg(prognum
, versnum
, procnum
, progname
, inproc
,
456 * All the following clnt_broadcast stuff is convulated; it supports
457 * the earlier calling style of the callback function
459 static pthread_key_t clnt_broadcast_key
= PTHREAD_ONCE_KEY_NP
;
460 static resultproc_t clnt_broadcast_result_main
;
463 * Need to translate the netbuf address into sockaddr_in address.
464 * Dont care about netid here.
468 rpc_wrap_bcast(char *resultp
, struct netbuf
*addr
, struct netconfig
*nconf
)
470 resultproc_t clnt_broadcast_result
;
472 clnt_broadcast_result
= thr_main()? clnt_broadcast_result_main
:
473 (resultproc_t
)pthread_getspecific(clnt_broadcast_key
);
474 return ((*clnt_broadcast_result
)(resultp
,
475 /* LINTED pointer cast */
476 (struct sockaddr_in
*)addr
->buf
));
480 * Broadcasts on UDP transport. Obsoleted by rpc_broadcast().
483 clnt_broadcast(rpcprog_t prog
, rpcvers_t vers
, rpcproc_t proc
, xdrproc_t xargs
,
484 caddr_t argsp
, xdrproc_t xresults
,
485 caddr_t resultsp
, resultproc_t eachresult
)
488 clnt_broadcast_result_main
= eachresult
;
490 (void) pthread_key_create_once_np(&clnt_broadcast_key
, NULL
);
491 (void) pthread_setspecific(clnt_broadcast_key
,
494 return (rpc_broadcast(prog
, vers
, proc
, xargs
, argsp
, xresults
,
495 resultsp
, (resultproc_t
)rpc_wrap_bcast
, "udp"));
499 * Create the client des authentication object. Obsoleted by
500 * authdes_seccreate().
503 authdes_create(char *servername
, uint_t window
, struct sockaddr_in
*syncaddr
,
506 char *hostname
= NULL
;
510 * Change addr to hostname, because that is the way
511 * new interface takes it.
513 struct netconfig
*nconf
;
514 struct netbuf nb_syncaddr
;
515 struct nd_hostservlist
*hlist
;
520 if ((nconf
= __rpc_getconfip("udp")) == NULL
&&
521 (nconf
= __rpc_getconfip("tcp")) == NULL
)
524 /* Transform sockaddr_in to netbuf */
525 if ((fd
= t_open(nconf
->nc_device
, O_RDWR
, &tinfo
)) == -1) {
526 (void) freenetconfigent(nconf
);
530 nb_syncaddr
.maxlen
= nb_syncaddr
.len
=
531 __rpc_get_a_size(tinfo
.addr
);
532 nb_syncaddr
.buf
= (char *)syncaddr
;
533 if (netdir_getbyaddr(nconf
, &hlist
, &nb_syncaddr
)) {
534 (void) freenetconfigent(nconf
);
537 if (hlist
&& hlist
->h_cnt
> 0 && hlist
->h_hostservs
)
538 hostname
= hlist
->h_hostservs
->h_host
;
539 nauth
= authdes_seccreate(servername
, window
, hostname
, ckey
);
540 (void) netdir_free((char *)hlist
, ND_HOSTSERVLIST
);
541 (void) freenetconfigent(nconf
);
545 return (authdes_seccreate(servername
, window
, hostname
, ckey
));