2 * Copyright (c) 2009, Sun Microsystems, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * - Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 * - Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12 * - Neither the name of Sun Microsystems, Inc. nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
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>
66 #include "un-namespace.h"
71 static CLIENT
*clnt_com_create(struct sockaddr_in
*, rpcprog_t
, rpcvers_t
,
72 int *, u_int
, u_int
, char *);
73 static SVCXPRT
*svc_com_create(int, u_int
, u_int
, char *);
74 static bool_t
rpc_wrap_bcast(char *, struct netbuf
*, struct netconfig
*);
77 #define IN4_LOCALHOST_STRING "127.0.0.1"
78 #define IN6_LOCALHOST_STRING "::1"
81 * A common clnt create routine
84 clnt_com_create(struct sockaddr_in
*raddr
, rpcprog_t prog
, rpcvers_t vers
,
85 int *sockp
, u_int sendsz
, u_int recvsz
, char *tp
)
90 struct netconfig
*nconf
;
91 struct netbuf bindaddr
;
93 mutex_lock(&rpcsoc_lock
);
94 if ((nconf
= __rpc_getconfip(tp
)) == NULL
) {
95 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
96 mutex_unlock(&rpcsoc_lock
);
99 if (fd
== RPC_ANYSOCK
) {
100 fd
= __rpc_nconf2fd(nconf
);
106 if (raddr
->sin_port
== 0) {
110 mutex_unlock(&rpcsoc_lock
); /* pmap_getport is recursive */
111 proto
= strcmp(tp
, "udp") == 0 ? IPPROTO_UDP
: IPPROTO_TCP
;
112 sport
= pmap_getport(raddr
, (u_long
)prog
, (u_long
)vers
,
117 raddr
->sin_port
= htons(sport
);
118 mutex_lock(&rpcsoc_lock
); /* pmap_getport is recursive */
121 /* Transform sockaddr_in to netbuf */
122 bindaddr
.maxlen
= bindaddr
.len
= sizeof (struct sockaddr_in
);
123 bindaddr
.buf
= raddr
;
125 bindresvport(fd
, NULL
);
126 cl
= clnt_tli_create(fd
, nconf
, &bindaddr
, prog
, vers
,
129 if (madefd
== TRUE
) {
131 * The fd should be closed while destroying the handle.
133 CLNT_CONTROL(cl
, CLSET_FD_CLOSE
, NULL
);
136 freenetconfigent(nconf
);
137 mutex_unlock(&rpcsoc_lock
);
143 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
144 rpc_createerr
.cf_error
.re_errno
= errno
;
146 err
: if (madefd
== TRUE
)
148 freenetconfigent(nconf
);
149 mutex_unlock(&rpcsoc_lock
);
154 clntudp_bufcreate(struct sockaddr_in
*raddr
, u_long prog
, u_long vers
,
155 struct timeval wait
, int *sockp
, u_int sendsz
, u_int recvsz
)
159 cl
= clnt_com_create(raddr
, (rpcprog_t
)prog
, (rpcvers_t
)vers
, sockp
,
160 sendsz
, recvsz
, "udp");
164 CLNT_CONTROL(cl
, CLSET_RETRY_TIMEOUT
, &wait
);
169 clntudp_create(struct sockaddr_in
*raddr
, u_long program
, u_long version
,
170 struct timeval wait
, int *sockp
)
173 return clntudp_bufcreate(raddr
, program
, version
, wait
, sockp
,
174 UDPMSGSIZE
, UDPMSGSIZE
);
178 clnttcp_create(struct sockaddr_in
*raddr
, u_long prog
, u_long vers
, int *sockp
,
179 u_int sendsz
, u_int recvsz
)
182 return clnt_com_create(raddr
, (rpcprog_t
)prog
, (rpcvers_t
)vers
, sockp
,
183 sendsz
, recvsz
, "tcp");
187 clntraw_create(u_long prog
, u_long vers
)
190 return clnt_raw_create((rpcprog_t
)prog
, (rpcvers_t
)vers
);
194 * A common server create routine
197 svc_com_create(int fd
, u_int sendsize
, u_int recvsize
, char *netid
)
199 struct netconfig
*nconf
;
203 struct sockaddr_in sin
;
205 if ((nconf
= __rpc_getconfip(netid
)) == NULL
) {
206 syslog(LOG_ERR
, "Could not get %s transport", netid
);
209 if (fd
== RPC_ANYSOCK
) {
210 fd
= __rpc_nconf2fd(nconf
);
212 freenetconfigent(nconf
);
214 "svc%s_create: could not open connection", netid
);
220 memset(&sin
, 0, sizeof sin
);
221 sin
.sin_family
= AF_INET
;
222 bindresvport(fd
, &sin
);
223 _listen(fd
, SOMAXCONN
);
224 svc
= svc_tli_create(fd
, nconf
, NULL
, sendsize
, recvsize
);
225 freenetconfigent(nconf
);
231 port
= (((struct sockaddr_in
*)svc
->xp_ltaddr
.buf
)->sin_port
);
232 svc
->xp_port
= ntohs(port
);
237 svctcp_create(int fd
, u_int sendsize
, u_int recvsize
)
240 return svc_com_create(fd
, sendsize
, recvsize
, "tcp");
244 svcudp_bufcreate(int fd
, u_int sendsz
, u_int recvsz
)
247 return svc_com_create(fd
, sendsz
, recvsz
, "udp");
251 svcfd_create(int fd
, u_int sendsize
, u_int recvsize
)
254 return svc_fd_create(fd
, sendsize
, recvsize
);
259 svcudp_create(int fd
)
262 return svc_com_create(fd
, UDPMSGSIZE
, UDPMSGSIZE
, "udp");
269 return svc_raw_create();
273 get_myaddress(struct sockaddr_in
*addr
)
276 memset((void *) addr
, 0, sizeof(*addr
));
277 addr
->sin_family
= AF_INET
;
278 addr
->sin_port
= htons(PMAPPORT
);
279 addr
->sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
284 * For connectionless "udp" transport. Obsoleted by rpc_call().
287 callrpc(const char *host
, int prognum
, int versnum
, int procnum
,
288 xdrproc_t inproc
, void *in
, xdrproc_t outproc
, void *out
)
291 return (int)rpc_call(host
, (rpcprog_t
)prognum
, (rpcvers_t
)versnum
,
292 (rpcproc_t
)procnum
, inproc
, in
, outproc
, out
, "udp");
296 * For connectionless kind of transport. Obsoleted by rpc_reg()
299 registerrpc(int prognum
, int versnum
, int procnum
, char *(*progname
)(char *),
300 xdrproc_t inproc
, xdrproc_t outproc
)
303 return rpc_reg((rpcprog_t
)prognum
, (rpcvers_t
)versnum
,
304 (rpcproc_t
)procnum
, progname
, inproc
, outproc
, "udp");
308 * All the following clnt_broadcast stuff is convulated; it supports
309 * the earlier calling style of the callback function
311 static thread_key_t clnt_broadcast_key
;
312 static resultproc_t clnt_broadcast_result_main
;
315 * Need to translate the netbuf address into sockaddr_in address.
316 * Dont care about netid here.
320 rpc_wrap_bcast(char *resultp
, /* results of the call */
321 struct netbuf
*addr
, /* address of the guy who responded */
322 struct netconfig
*nconf
) /* Netconf of the transport */
324 resultproc_t clnt_broadcast_result
;
326 if (strcmp(nconf
->nc_netid
, "udp"))
329 clnt_broadcast_result
= clnt_broadcast_result_main
;
331 clnt_broadcast_result
= (resultproc_t
)thr_getspecific(clnt_broadcast_key
);
332 return (*clnt_broadcast_result
)(resultp
,
333 (struct sockaddr_in
*)addr
->buf
);
337 * Broadcasts on UDP transport. Obsoleted by rpc_broadcast().
340 clnt_broadcast(u_long prog
, /* program number */
341 u_long vers
, /* version number */
342 u_long proc
, /* procedure number */
343 xdrproc_t xargs
, /* xdr routine for args */
344 void *argsp
, /* pointer to args */
345 xdrproc_t xresults
, /* xdr routine for results */
346 void *resultsp
, /* pointer to results */
347 resultproc_t eachresult
) /* call with each result obtained */
351 clnt_broadcast_result_main
= eachresult
;
353 if (clnt_broadcast_key
== 0) {
354 mutex_lock(&tsd_lock
);
355 if (clnt_broadcast_key
== 0)
356 thr_keycreate(&clnt_broadcast_key
, free
);
357 mutex_unlock(&tsd_lock
);
359 thr_setspecific(clnt_broadcast_key
, (void *) eachresult
);
361 return rpc_broadcast((rpcprog_t
)prog
, (rpcvers_t
)vers
,
362 (rpcproc_t
)proc
, xargs
, argsp
, xresults
, resultsp
,
363 (resultproc_t
) rpc_wrap_bcast
, "udp");
367 * Create the client des authentication object. Obsoleted by
368 * authdes_seccreate().
371 authdes_create(char *servername
, /* network name of server */
372 u_int window
, /* time to live */
373 struct sockaddr
*syncaddr
,/* optional hostaddr to sync with */
374 des_block
*ckey
) /* optional conversation key to use */
378 char hostname
[NI_MAXHOST
];
382 * Change addr to hostname, because that is the way
383 * new interface takes it.
385 if (getnameinfo(syncaddr
, syncaddr
->sa_len
, hostname
,
386 sizeof hostname
, NULL
, 0, 0) != 0)
389 nauth
= authdes_seccreate(servername
, window
, hostname
, ckey
);
393 dummy
= authdes_seccreate(servername
, window
, NULL
, ckey
);
398 * Create a client handle for a unix connection. Obsoleted by clnt_vc_create()
401 clntunix_create(struct sockaddr_un
*raddr
, u_long prog
, u_long vers
, int *sockp
,
402 u_int sendsz
, u_int recvsz
)
404 struct netbuf
*svcaddr
;
410 if ((raddr
->sun_len
== 0) ||
411 ((svcaddr
= malloc(sizeof(struct netbuf
))) == NULL
) ||
412 ((svcaddr
->buf
= malloc(sizeof(struct sockaddr_un
))) == NULL
)) {
415 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
416 rpc_createerr
.cf_error
.re_errno
= errno
;
420 *sockp
= _socket(AF_LOCAL
, SOCK_STREAM
, 0);
421 len
= raddr
->sun_len
= SUN_LEN(raddr
);
422 if ((*sockp
< 0) || (_connect(*sockp
,
423 (struct sockaddr
*)raddr
, len
) < 0)) {
424 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
425 rpc_createerr
.cf_error
.re_errno
= errno
;
431 svcaddr
->buf
= raddr
;
432 svcaddr
->len
= raddr
->sun_len
;
433 svcaddr
->maxlen
= sizeof (struct sockaddr_un
);
434 cl
= clnt_vc_create(*sockp
, svcaddr
, prog
,
435 vers
, sendsz
, recvsz
);
443 * Creates, registers, and returns a (rpc) unix based transporter.
444 * Obsoleted by svc_vc_create().
447 svcunix_create(int sock
, u_int sendsize
, u_int recvsize
, char *path
)
449 struct netconfig
*nconf
;
451 struct sockaddr_un sun
;
458 localhandle
= setnetconfig();
459 while ((nconf
= getnetconfig(localhandle
)) != NULL
) {
460 if (nconf
->nc_protofmly
!= NULL
&&
461 strcmp(nconf
->nc_protofmly
, NC_LOOPBACK
) == 0)
467 if ((sock
= __rpc_nconf2fd(nconf
)) < 0)
470 memset(&sun
, 0, sizeof sun
);
471 sun
.sun_family
= AF_LOCAL
;
472 if (strlcpy(sun
.sun_path
, path
, sizeof(sun
.sun_path
)) >=
473 sizeof(sun
.sun_path
))
475 sun
.sun_len
= SUN_LEN(&sun
);
476 addrlen
= sizeof (struct sockaddr_un
);
477 sa
= (struct sockaddr
*)&sun
;
479 if (_bind(sock
, sa
, addrlen
) < 0)
482 taddr
.addr
.len
= taddr
.addr
.maxlen
= addrlen
;
483 taddr
.addr
.buf
= malloc(addrlen
);
484 if (taddr
.addr
.buf
== NULL
)
486 memcpy(taddr
.addr
.buf
, sa
, addrlen
);
488 if (nconf
->nc_semantics
!= NC_TPI_CLTS
) {
489 if (_listen(sock
, SOMAXCONN
) < 0) {
490 free(taddr
.addr
.buf
);
495 xprt
= (SVCXPRT
*)svc_tli_create(sock
, nconf
, &taddr
, sendsize
, recvsize
);
498 endnetconfig(localhandle
);
503 * Like svunix_create(), except the routine takes any *open* UNIX file
504 * descriptor as its first input. Obsoleted by svc_fd_create();
507 svcunixfd_create(int fd
, u_int sendsize
, u_int recvsize
)
509 return (svc_fd_create(fd
, sendsize
, recvsize
));