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 $
35 * Copyright (c) 1986-1991 by Sun Microsystems Inc.
36 * In addition, portions of such source code were derived from Berkeley
37 * 4.3 BSD under license from the Regents of the University of
45 * The backward compatibility routines for the earlier implementation
46 * of RPC, where the only transports supported were tcp/ip and udp/ip.
47 * Based on berkeley socket abstraction, now implemented on the top
51 #include "namespace.h"
52 #include "reentrant.h"
53 #include <sys/types.h>
54 #include <sys/socket.h>
57 #include <rpc/pmap_clnt.h>
58 #include <rpc/pmap_prot.h>
59 #include <rpc/nettype.h>
61 #include <netinet/in.h>
68 #include "un-namespace.h"
73 static CLIENT
*clnt_com_create(struct sockaddr_in
*, rpcprog_t
, rpcvers_t
,
74 int *, u_int
, u_int
, char *);
75 static SVCXPRT
*svc_com_create(int, u_int
, u_int
, char *);
76 static bool_t
rpc_wrap_bcast(char *, struct netbuf
*, struct netconfig
*);
79 #define IN4_LOCALHOST_STRING "127.0.0.1"
80 #define IN6_LOCALHOST_STRING "::1"
83 * A common clnt create routine
86 clnt_com_create(struct sockaddr_in
*raddr
, rpcprog_t prog
, rpcvers_t vers
,
87 int *sockp
, u_int sendsz
, u_int recvsz
, char *tp
)
92 struct netconfig
*nconf
;
93 struct netbuf bindaddr
;
95 mutex_lock(&rpcsoc_lock
);
96 if ((nconf
= __rpc_getconfip(tp
)) == NULL
) {
97 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
98 mutex_unlock(&rpcsoc_lock
);
101 if (fd
== RPC_ANYSOCK
) {
102 fd
= __rpc_nconf2fd(nconf
);
108 if (raddr
->sin_port
== 0) {
112 mutex_unlock(&rpcsoc_lock
); /* pmap_getport is recursive */
113 proto
= strcmp(tp
, "udp") == 0 ? IPPROTO_UDP
: IPPROTO_TCP
;
114 sport
= pmap_getport(raddr
, (u_long
)prog
, (u_long
)vers
,
119 raddr
->sin_port
= htons(sport
);
120 mutex_lock(&rpcsoc_lock
); /* pmap_getport is recursive */
123 /* Transform sockaddr_in to netbuf */
124 bindaddr
.maxlen
= bindaddr
.len
= sizeof (struct sockaddr_in
);
125 bindaddr
.buf
= raddr
;
127 bindresvport(fd
, NULL
);
128 cl
= clnt_tli_create(fd
, nconf
, &bindaddr
, prog
, vers
,
131 if (madefd
== TRUE
) {
133 * The fd should be closed while destroying the handle.
135 CLNT_CONTROL(cl
, CLSET_FD_CLOSE
, NULL
);
138 freenetconfigent(nconf
);
139 mutex_unlock(&rpcsoc_lock
);
145 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
146 rpc_createerr
.cf_error
.re_errno
= errno
;
148 err
: if (madefd
== TRUE
)
150 freenetconfigent(nconf
);
151 mutex_unlock(&rpcsoc_lock
);
156 clntudp_bufcreate(struct sockaddr_in
*raddr
, u_long prog
, u_long vers
,
157 struct timeval wait
, int *sockp
, u_int sendsz
, u_int recvsz
)
161 cl
= clnt_com_create(raddr
, (rpcprog_t
)prog
, (rpcvers_t
)vers
, sockp
,
162 sendsz
, recvsz
, "udp");
166 CLNT_CONTROL(cl
, CLSET_RETRY_TIMEOUT
, &wait
);
171 clntudp_create(struct sockaddr_in
*raddr
, u_long program
, u_long version
,
172 struct timeval wait
, int *sockp
)
175 return clntudp_bufcreate(raddr
, program
, version
, wait
, sockp
,
176 UDPMSGSIZE
, UDPMSGSIZE
);
180 clnttcp_create(struct sockaddr_in
*raddr
, u_long prog
, u_long vers
, int *sockp
,
181 u_int sendsz
, u_int recvsz
)
184 return clnt_com_create(raddr
, (rpcprog_t
)prog
, (rpcvers_t
)vers
, sockp
,
185 sendsz
, recvsz
, "tcp");
189 clntraw_create(u_long prog
, u_long vers
)
192 return clnt_raw_create((rpcprog_t
)prog
, (rpcvers_t
)vers
);
196 * A common server create routine
199 svc_com_create(int fd
, u_int sendsize
, u_int recvsize
, char *netid
)
201 struct netconfig
*nconf
;
205 struct sockaddr_in sin
;
207 if ((nconf
= __rpc_getconfip(netid
)) == NULL
) {
208 syslog(LOG_ERR
, "Could not get %s transport", netid
);
211 if (fd
== RPC_ANYSOCK
) {
212 fd
= __rpc_nconf2fd(nconf
);
214 freenetconfigent(nconf
);
216 "svc%s_create: could not open connection", netid
);
222 memset(&sin
, 0, sizeof sin
);
223 sin
.sin_family
= AF_INET
;
224 bindresvport(fd
, &sin
);
225 _listen(fd
, SOMAXCONN
);
226 svc
= svc_tli_create(fd
, nconf
, NULL
, sendsize
, recvsize
);
227 freenetconfigent(nconf
);
233 port
= (((struct sockaddr_in
*)svc
->xp_ltaddr
.buf
)->sin_port
);
234 svc
->xp_port
= ntohs(port
);
239 svctcp_create(int fd
, u_int sendsize
, u_int recvsize
)
242 return svc_com_create(fd
, sendsize
, recvsize
, "tcp");
246 svcudp_bufcreate(int fd
, u_int sendsz
, u_int recvsz
)
249 return svc_com_create(fd
, sendsz
, recvsz
, "udp");
253 svcfd_create(int fd
, u_int sendsize
, u_int recvsize
)
256 return svc_fd_create(fd
, sendsize
, recvsize
);
261 svcudp_create(int fd
)
264 return svc_com_create(fd
, UDPMSGSIZE
, UDPMSGSIZE
, "udp");
271 return svc_raw_create();
275 get_myaddress(struct sockaddr_in
*addr
)
278 memset((void *) addr
, 0, sizeof(*addr
));
279 addr
->sin_family
= AF_INET
;
280 addr
->sin_port
= htons(PMAPPORT
);
281 addr
->sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
286 * For connectionless "udp" transport. Obsoleted by rpc_call().
289 callrpc(const char *host
, int prognum
, int versnum
, int procnum
,
290 xdrproc_t inproc
, void *in
, xdrproc_t outproc
, void *out
)
293 return (int)rpc_call(host
, (rpcprog_t
)prognum
, (rpcvers_t
)versnum
,
294 (rpcproc_t
)procnum
, inproc
, in
, outproc
, out
, "udp");
298 * For connectionless kind of transport. Obsoleted by rpc_reg()
301 registerrpc(int prognum
, int versnum
, int procnum
, char *(*progname
)(char *),
302 xdrproc_t inproc
, xdrproc_t outproc
)
305 return rpc_reg((rpcprog_t
)prognum
, (rpcvers_t
)versnum
,
306 (rpcproc_t
)procnum
, progname
, inproc
, outproc
, "udp");
310 * All the following clnt_broadcast stuff is convulated; it supports
311 * the earlier calling style of the callback function
313 static thread_key_t clnt_broadcast_key
;
314 static resultproc_t clnt_broadcast_result_main
;
317 * Need to translate the netbuf address into sockaddr_in address.
318 * Dont care about netid here.
322 rpc_wrap_bcast(char *resultp
, /* results of the call */
323 struct netbuf
*addr
, /* address of the guy who responded */
324 struct netconfig
*nconf
) /* Netconf of the transport */
326 resultproc_t clnt_broadcast_result
;
328 if (strcmp(nconf
->nc_netid
, "udp"))
331 clnt_broadcast_result
= clnt_broadcast_result_main
;
333 clnt_broadcast_result
= (resultproc_t
)thr_getspecific(clnt_broadcast_key
);
334 return (*clnt_broadcast_result
)(resultp
,
335 (struct sockaddr_in
*)addr
->buf
);
339 * Broadcasts on UDP transport. Obsoleted by rpc_broadcast().
342 clnt_broadcast(u_long prog
, /* program number */
343 u_long vers
, /* version number */
344 u_long proc
, /* procedure number */
345 xdrproc_t xargs
, /* xdr routine for args */
346 void *argsp
, /* pointer to args */
347 xdrproc_t xresults
, /* xdr routine for results */
348 void *resultsp
, /* pointer to results */
349 resultproc_t eachresult
) /* call with each result obtained */
353 clnt_broadcast_result_main
= eachresult
;
355 if (clnt_broadcast_key
== 0) {
356 mutex_lock(&tsd_lock
);
357 if (clnt_broadcast_key
== 0)
358 thr_keycreate(&clnt_broadcast_key
, free
);
359 mutex_unlock(&tsd_lock
);
361 thr_setspecific(clnt_broadcast_key
, (void *) eachresult
);
363 return rpc_broadcast((rpcprog_t
)prog
, (rpcvers_t
)vers
,
364 (rpcproc_t
)proc
, xargs
, argsp
, xresults
, resultsp
,
365 (resultproc_t
) rpc_wrap_bcast
, "udp");
369 * Create the client des authentication object. Obsoleted by
370 * authdes_seccreate().
373 authdes_create(char *servername
, /* network name of server */
374 u_int window
, /* time to live */
375 struct sockaddr
*syncaddr
,/* optional hostaddr to sync with */
376 des_block
*ckey
) /* optional conversation key to use */
380 char hostname
[NI_MAXHOST
];
384 * Change addr to hostname, because that is the way
385 * new interface takes it.
387 if (getnameinfo(syncaddr
, syncaddr
->sa_len
, hostname
,
388 sizeof hostname
, NULL
, 0, 0) != 0)
391 nauth
= authdes_seccreate(servername
, window
, hostname
, ckey
);
395 dummy
= authdes_seccreate(servername
, window
, NULL
, ckey
);
400 * Create a client handle for a unix connection. Obsoleted by clnt_vc_create()
403 clntunix_create(struct sockaddr_un
*raddr
, u_long prog
, u_long vers
, int *sockp
,
404 u_int sendsz
, u_int recvsz
)
406 struct netbuf
*svcaddr
;
407 struct netconfig
*nconf
;
414 if ((raddr
->sun_len
== 0) ||
415 ((svcaddr
= malloc(sizeof(struct netbuf
))) == NULL
) ||
416 ((svcaddr
->buf
= malloc(sizeof(struct sockaddr_un
))) == NULL
)) {
419 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
420 rpc_createerr
.cf_error
.re_errno
= errno
;
424 *sockp
= _socket(AF_LOCAL
, SOCK_STREAM
, 0);
425 len
= raddr
->sun_len
= SUN_LEN(raddr
);
426 if ((*sockp
< 0) || (_connect(*sockp
,
427 (struct sockaddr
*)raddr
, len
) < 0)) {
428 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
429 rpc_createerr
.cf_error
.re_errno
= errno
;
435 svcaddr
->buf
= raddr
;
436 svcaddr
->len
= raddr
->sun_len
;
437 svcaddr
->maxlen
= sizeof (struct sockaddr_un
);
438 cl
= clnt_vc_create(*sockp
, svcaddr
, prog
,
439 vers
, sendsz
, recvsz
);
447 * Creates, registers, and returns a (rpc) unix based transporter.
448 * Obsoleted by svc_vc_create().
451 svcunix_create(int sock
, u_int sendsize
, u_int recvsize
, char *path
)
453 struct netconfig
*nconf
;
455 struct sockaddr_un sun
;
461 xprt
= (SVCXPRT
*)NULL
;
462 localhandle
= setnetconfig();
463 while ((nconf
= getnetconfig(localhandle
)) != NULL
) {
464 if (nconf
->nc_protofmly
!= NULL
&&
465 strcmp(nconf
->nc_protofmly
, NC_LOOPBACK
) == 0)
471 if ((sock
= __rpc_nconf2fd(nconf
)) < 0)
474 memset(&sun
, 0, sizeof sun
);
475 sun
.sun_family
= AF_LOCAL
;
476 if (strlcpy(sun
.sun_path
, path
, sizeof(sun
.sun_path
)) >=
477 sizeof(sun
.sun_path
))
479 sun
.sun_len
= SUN_LEN(&sun
);
480 addrlen
= sizeof (struct sockaddr_un
);
481 sa
= (struct sockaddr
*)&sun
;
483 if (_bind(sock
, sa
, addrlen
) < 0)
486 taddr
.addr
.len
= taddr
.addr
.maxlen
= addrlen
;
487 taddr
.addr
.buf
= malloc(addrlen
);
488 if (taddr
.addr
.buf
== NULL
)
490 memcpy(taddr
.addr
.buf
, sa
, addrlen
);
492 if (nconf
->nc_semantics
!= NC_TPI_CLTS
) {
493 if (_listen(sock
, SOMAXCONN
) < 0) {
494 free(taddr
.addr
.buf
);
499 xprt
= (SVCXPRT
*)svc_tli_create(sock
, nconf
, &taddr
, sendsize
, recvsize
);
502 endnetconfig(localhandle
);
507 * Like svunix_create(), except the routine takes any *open* UNIX file
508 * descriptor as its first input. Obsoleted by svc_fd_create();
511 svcunixfd_create(int fd
, u_int sendsize
, u_int recvsize
)
513 return (svc_fd_create(fd
, sendsize
, recvsize
));