2 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3 * unrestricted use provided that this legend is included on all tape
4 * media and as a part of the software program in whole or part. Users
5 * may copy or modify Sun RPC without charge, but are not authorized
6 * to license or distribute it to anyone else except as part of a product or
7 * program developed by the user.
9 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
10 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
11 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
13 * Sun RPC is provided with no support and without any obligation on the
14 * part of Sun Microsystems, Inc. to assist in its use, correction,
15 * modification or enhancement.
17 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
18 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
19 * OR ANY PART THEREOF.
21 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
22 * or profits or other special, indirect and consequential damages, even if
23 * Sun has been advised of the possibility of such damages.
25 * Sun Microsystems, Inc.
27 * Mountain View, California 94043
28 * @(#)rpc_soc.c 1.17 94/04/24 SMI; 1.41 89/05/02 Copyr 1988 Sun Micro
29 * $NetBSD: rpc_soc.c,v 1.6 2000/07/06 03:10:35 christos Exp $
30 * $FreeBSD: src/lib/libc/rpc/rpc_soc.c,v 1.15 2006/02/27 22:10:59 deischen Exp $
34 * Copyright (c) 1986-1991 by Sun Microsystems Inc.
35 * In addition, portions of such source code were derived from Berkeley
36 * 4.3 BSD under license from the Regents of the University of
44 * The backward compatibility routines for the earlier implementation
45 * of RPC, where the only transports supported were tcp/ip and udp/ip.
46 * Based on berkeley socket abstraction, now implemented on the top
50 #include "namespace.h"
51 #include "reentrant.h"
52 #include <sys/types.h>
53 #include <sys/socket.h>
56 #include <rpc/pmap_clnt.h>
57 #include <rpc/pmap_prot.h>
58 #include <rpc/nettype.h>
60 #include <netinet/in.h>
67 #include "un-namespace.h"
72 static CLIENT
*clnt_com_create(struct sockaddr_in
*, rpcprog_t
, rpcvers_t
,
73 int *, u_int
, u_int
, char *);
74 static SVCXPRT
*svc_com_create(int, u_int
, u_int
, char *);
75 static bool_t
rpc_wrap_bcast(char *, struct netbuf
*, struct netconfig
*);
78 #define IN4_LOCALHOST_STRING "127.0.0.1"
79 #define IN6_LOCALHOST_STRING "::1"
82 * A common clnt create routine
85 clnt_com_create(struct sockaddr_in
*raddr
, rpcprog_t prog
, rpcvers_t vers
,
86 int *sockp
, u_int sendsz
, u_int recvsz
, char *tp
)
91 struct netconfig
*nconf
;
92 struct netbuf bindaddr
;
94 mutex_lock(&rpcsoc_lock
);
95 if ((nconf
= __rpc_getconfip(tp
)) == NULL
) {
96 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
97 mutex_unlock(&rpcsoc_lock
);
100 if (fd
== RPC_ANYSOCK
) {
101 fd
= __rpc_nconf2fd(nconf
);
107 if (raddr
->sin_port
== 0) {
111 mutex_unlock(&rpcsoc_lock
); /* pmap_getport is recursive */
112 proto
= strcmp(tp
, "udp") == 0 ? IPPROTO_UDP
: IPPROTO_TCP
;
113 sport
= pmap_getport(raddr
, (u_long
)prog
, (u_long
)vers
,
118 raddr
->sin_port
= htons(sport
);
119 mutex_lock(&rpcsoc_lock
); /* pmap_getport is recursive */
122 /* Transform sockaddr_in to netbuf */
123 bindaddr
.maxlen
= bindaddr
.len
= sizeof (struct sockaddr_in
);
124 bindaddr
.buf
= raddr
;
126 bindresvport(fd
, NULL
);
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 CLNT_CONTROL(cl
, CLSET_FD_CLOSE
, NULL
);
137 freenetconfigent(nconf
);
138 mutex_unlock(&rpcsoc_lock
);
144 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
145 rpc_createerr
.cf_error
.re_errno
= errno
;
147 err
: if (madefd
== TRUE
)
149 freenetconfigent(nconf
);
150 mutex_unlock(&rpcsoc_lock
);
155 clntudp_bufcreate(struct sockaddr_in
*raddr
, u_long prog
, u_long vers
,
156 struct timeval wait
, int *sockp
, u_int sendsz
, u_int recvsz
)
160 cl
= clnt_com_create(raddr
, (rpcprog_t
)prog
, (rpcvers_t
)vers
, sockp
,
161 sendsz
, recvsz
, "udp");
165 CLNT_CONTROL(cl
, CLSET_RETRY_TIMEOUT
, &wait
);
170 clntudp_create(struct sockaddr_in
*raddr
, u_long program
, u_long version
,
171 struct timeval wait
, int *sockp
)
174 return clntudp_bufcreate(raddr
, program
, version
, wait
, sockp
,
175 UDPMSGSIZE
, UDPMSGSIZE
);
179 clnttcp_create(struct sockaddr_in
*raddr
, u_long prog
, u_long vers
, int *sockp
,
180 u_int sendsz
, u_int recvsz
)
183 return clnt_com_create(raddr
, (rpcprog_t
)prog
, (rpcvers_t
)vers
, sockp
,
184 sendsz
, recvsz
, "tcp");
188 clntraw_create(u_long prog
, u_long vers
)
191 return clnt_raw_create((rpcprog_t
)prog
, (rpcvers_t
)vers
);
195 * A common server create routine
198 svc_com_create(int fd
, u_int sendsize
, u_int recvsize
, char *netid
)
200 struct netconfig
*nconf
;
204 struct sockaddr_in sin
;
206 if ((nconf
= __rpc_getconfip(netid
)) == NULL
) {
207 syslog(LOG_ERR
, "Could not get %s transport", netid
);
210 if (fd
== RPC_ANYSOCK
) {
211 fd
= __rpc_nconf2fd(nconf
);
213 freenetconfigent(nconf
);
215 "svc%s_create: could not open connection", netid
);
221 memset(&sin
, 0, sizeof sin
);
222 sin
.sin_family
= AF_INET
;
223 bindresvport(fd
, &sin
);
224 _listen(fd
, SOMAXCONN
);
225 svc
= svc_tli_create(fd
, nconf
, NULL
, sendsize
, recvsize
);
226 freenetconfigent(nconf
);
232 port
= (((struct sockaddr_in
*)svc
->xp_ltaddr
.buf
)->sin_port
);
233 svc
->xp_port
= ntohs(port
);
238 svctcp_create(int fd
, u_int sendsize
, u_int recvsize
)
241 return svc_com_create(fd
, sendsize
, recvsize
, "tcp");
245 svcudp_bufcreate(int fd
, u_int sendsz
, u_int recvsz
)
248 return svc_com_create(fd
, sendsz
, recvsz
, "udp");
252 svcfd_create(int fd
, u_int sendsize
, u_int recvsize
)
255 return svc_fd_create(fd
, sendsize
, recvsize
);
260 svcudp_create(int fd
)
263 return svc_com_create(fd
, UDPMSGSIZE
, UDPMSGSIZE
, "udp");
270 return svc_raw_create();
274 get_myaddress(struct sockaddr_in
*addr
)
277 memset((void *) addr
, 0, sizeof(*addr
));
278 addr
->sin_family
= AF_INET
;
279 addr
->sin_port
= htons(PMAPPORT
);
280 addr
->sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
285 * For connectionless "udp" transport. Obsoleted by rpc_call().
288 callrpc(const char *host
, int prognum
, int versnum
, int procnum
,
289 xdrproc_t inproc
, void *in
, xdrproc_t outproc
, void *out
)
292 return (int)rpc_call(host
, (rpcprog_t
)prognum
, (rpcvers_t
)versnum
,
293 (rpcproc_t
)procnum
, inproc
, in
, outproc
, out
, "udp");
297 * For connectionless kind of transport. Obsoleted by rpc_reg()
300 registerrpc(int prognum
, int versnum
, int procnum
, char *(*progname
)(char *),
301 xdrproc_t inproc
, xdrproc_t outproc
)
304 return rpc_reg((rpcprog_t
)prognum
, (rpcvers_t
)versnum
,
305 (rpcproc_t
)procnum
, progname
, inproc
, outproc
, "udp");
309 * All the following clnt_broadcast stuff is convulated; it supports
310 * the earlier calling style of the callback function
312 static thread_key_t clnt_broadcast_key
;
313 static resultproc_t clnt_broadcast_result_main
;
316 * Need to translate the netbuf address into sockaddr_in address.
317 * Dont care about netid here.
321 rpc_wrap_bcast(char *resultp
, /* results of the call */
322 struct netbuf
*addr
, /* address of the guy who responded */
323 struct netconfig
*nconf
) /* Netconf of the transport */
325 resultproc_t clnt_broadcast_result
;
327 if (strcmp(nconf
->nc_netid
, "udp"))
330 clnt_broadcast_result
= clnt_broadcast_result_main
;
332 clnt_broadcast_result
= (resultproc_t
)thr_getspecific(clnt_broadcast_key
);
333 return (*clnt_broadcast_result
)(resultp
,
334 (struct sockaddr_in
*)addr
->buf
);
338 * Broadcasts on UDP transport. Obsoleted by rpc_broadcast().
341 clnt_broadcast(u_long prog
, /* program number */
342 u_long vers
, /* version number */
343 u_long proc
, /* procedure number */
344 xdrproc_t xargs
, /* xdr routine for args */
345 void *argsp
, /* pointer to args */
346 xdrproc_t xresults
, /* xdr routine for results */
347 void *resultsp
, /* pointer to results */
348 resultproc_t eachresult
) /* call with each result obtained */
352 clnt_broadcast_result_main
= eachresult
;
354 if (clnt_broadcast_key
== 0) {
355 mutex_lock(&tsd_lock
);
356 if (clnt_broadcast_key
== 0)
357 thr_keycreate(&clnt_broadcast_key
, free
);
358 mutex_unlock(&tsd_lock
);
360 thr_setspecific(clnt_broadcast_key
, (void *) eachresult
);
362 return rpc_broadcast((rpcprog_t
)prog
, (rpcvers_t
)vers
,
363 (rpcproc_t
)proc
, xargs
, argsp
, xresults
, resultsp
,
364 (resultproc_t
) rpc_wrap_bcast
, "udp");
368 * Create the client des authentication object. Obsoleted by
369 * authdes_seccreate().
372 authdes_create(char *servername
, /* network name of server */
373 u_int window
, /* time to live */
374 struct sockaddr
*syncaddr
,/* optional hostaddr to sync with */
375 des_block
*ckey
) /* optional conversation key to use */
379 char hostname
[NI_MAXHOST
];
383 * Change addr to hostname, because that is the way
384 * new interface takes it.
386 if (getnameinfo(syncaddr
, syncaddr
->sa_len
, hostname
,
387 sizeof hostname
, NULL
, 0, 0) != 0)
390 nauth
= authdes_seccreate(servername
, window
, hostname
, ckey
);
394 dummy
= authdes_seccreate(servername
, window
, NULL
, ckey
);
399 * Create a client handle for a unix connection. Obsoleted by clnt_vc_create()
402 clntunix_create(struct sockaddr_un
*raddr
, u_long prog
, u_long vers
, int *sockp
,
403 u_int sendsz
, u_int recvsz
)
405 struct netbuf
*svcaddr
;
406 struct netconfig
*nconf
;
413 if ((raddr
->sun_len
== 0) ||
414 ((svcaddr
= malloc(sizeof(struct netbuf
))) == NULL
) ||
415 ((svcaddr
->buf
= malloc(sizeof(struct sockaddr_un
))) == NULL
)) {
418 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
419 rpc_createerr
.cf_error
.re_errno
= errno
;
423 *sockp
= _socket(AF_LOCAL
, SOCK_STREAM
, 0);
424 len
= raddr
->sun_len
= SUN_LEN(raddr
);
425 if ((*sockp
< 0) || (_connect(*sockp
,
426 (struct sockaddr
*)raddr
, len
) < 0)) {
427 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
428 rpc_createerr
.cf_error
.re_errno
= errno
;
434 svcaddr
->buf
= raddr
;
435 svcaddr
->len
= raddr
->sun_len
;
436 svcaddr
->maxlen
= sizeof (struct sockaddr_un
);
437 cl
= clnt_vc_create(*sockp
, svcaddr
, prog
,
438 vers
, sendsz
, recvsz
);
446 * Creates, registers, and returns a (rpc) unix based transporter.
447 * Obsoleted by svc_vc_create().
450 svcunix_create(int sock
, u_int sendsize
, u_int recvsize
, char *path
)
452 struct netconfig
*nconf
;
454 struct sockaddr_un sun
;
461 localhandle
= setnetconfig();
462 while ((nconf
= getnetconfig(localhandle
)) != NULL
) {
463 if (nconf
->nc_protofmly
!= NULL
&&
464 strcmp(nconf
->nc_protofmly
, NC_LOOPBACK
) == 0)
470 if ((sock
= __rpc_nconf2fd(nconf
)) < 0)
473 memset(&sun
, 0, sizeof sun
);
474 sun
.sun_family
= AF_LOCAL
;
475 if (strlcpy(sun
.sun_path
, path
, sizeof(sun
.sun_path
)) >=
476 sizeof(sun
.sun_path
))
478 sun
.sun_len
= SUN_LEN(&sun
);
479 addrlen
= sizeof (struct sockaddr_un
);
480 sa
= (struct sockaddr
*)&sun
;
482 if (_bind(sock
, sa
, addrlen
) < 0)
485 taddr
.addr
.len
= taddr
.addr
.maxlen
= addrlen
;
486 taddr
.addr
.buf
= malloc(addrlen
);
487 if (taddr
.addr
.buf
== NULL
)
489 memcpy(taddr
.addr
.buf
, sa
, addrlen
);
491 if (nconf
->nc_semantics
!= NC_TPI_CLTS
) {
492 if (_listen(sock
, SOMAXCONN
) < 0) {
493 free(taddr
.addr
.buf
);
498 xprt
= (SVCXPRT
*)svc_tli_create(sock
, nconf
, &taddr
, sendsize
, recvsize
);
501 endnetconfig(localhandle
);
506 * Like svunix_create(), except the routine takes any *open* UNIX file
507 * descriptor as its first input. Obsoleted by svc_fd_create();
510 svcunixfd_create(int fd
, u_int sendsize
, u_int recvsize
)
512 return (svc_fd_create(fd
, sendsize
, recvsize
));