d201fe46e3
adding (weak definitions to) stubs for some of the pthread functions. If the threads library is linked in, the real pthread functions will pulled in. Use the following convention for system calls wrapped by the threads library: __sys_foo - actual system call _foo - weak definition to __sys_foo foo - weak definition to __sys_foo Change all libc uses of system calls wrapped by the threads library from foo to _foo. In order to define the prototypes for _foo(), we introduce namespace.h and un-namespace.h (suggested by bde). All files that need to reference these system calls, should include namespace.h before any standard includes, then include un-namespace.h after the standard includes and before any local includes. <db.h> is an exception and shouldn't be included in between namespace.h and un-namespace.h namespace.h will define foo to _foo, and un-namespace.h will undefine foo. Try to eliminate some of the recursive calls to MT-safe functions in libc/stdio in preparation for adding a mutex to FILE. We have recursive mutexes, but would like to avoid using them if possible. Remove uneeded includes of <errno.h> from a few files. Add $FreeBSD$ to a few files in order to pass commitprep. Approved by: -arch
419 lines
12 KiB
C
419 lines
12 KiB
C
/*
|
|
* Sun RPC is a product of Sun Microsystems, Inc. and is provided for
|
|
* unrestricted use provided that this legend is included on all tape
|
|
* media and as a part of the software program in whole or part. Users
|
|
* may copy or modify Sun RPC without charge, but are not authorized
|
|
* to license or distribute it to anyone else except as part of a product or
|
|
* program developed by the user.
|
|
*
|
|
* SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
|
|
* WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
|
|
*
|
|
* Sun RPC is provided with no support and without any obligation on the
|
|
* part of Sun Microsystems, Inc. to assist in its use, correction,
|
|
* modification or enhancement.
|
|
*
|
|
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
|
|
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
|
|
* OR ANY PART THEREOF.
|
|
*
|
|
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
|
|
* or profits or other special, indirect and consequential damages, even if
|
|
* Sun has been advised of the possibility of such damages.
|
|
*
|
|
* Sun Microsystems, Inc.
|
|
* 2550 Garcia Avenue
|
|
* Mountain View, California 94043
|
|
*/
|
|
|
|
#if defined(LIBC_SCCS) && !defined(lint)
|
|
/*static char *sccsid = "from: @(#)pmap_rmt.c 1.21 87/08/27 Copyr 1984 Sun Micro";*/
|
|
/*static char *sccsid = "from: @(#)pmap_rmt.c 2.2 88/08/01 4.0 RPCSRC";*/
|
|
static char *rcsid = "$FreeBSD$";
|
|
#endif
|
|
|
|
/*
|
|
* pmap_rmt.c
|
|
* Client interface to pmap rpc service.
|
|
* remote call and broadcast service
|
|
*
|
|
* Copyright (C) 1984, Sun Microsystems, Inc.
|
|
*/
|
|
|
|
#include "namespace.h"
|
|
#include <rpc/rpc.h>
|
|
#include <rpc/pmap_prot.h>
|
|
#include <rpc/pmap_clnt.h>
|
|
#include <rpc/pmap_rmt.h>
|
|
#include <sys/socket.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <net/if.h>
|
|
#include <sys/ioctl.h>
|
|
#include <arpa/inet.h>
|
|
#include "un-namespace.h"
|
|
|
|
#define MAX_BROADCAST_SIZE 1400
|
|
|
|
static struct timeval timeout = { 3, 0 };
|
|
|
|
/*
|
|
* pmapper remote-call-service interface.
|
|
* This routine is used to call the pmapper remote call service
|
|
* which will look up a service program in the port maps, and then
|
|
* remotely call that routine with the given parameters. This allows
|
|
* programs to do a lookup and call in one step.
|
|
*/
|
|
enum clnt_stat
|
|
pmap_rmtcall(addr, prog, vers, proc, xdrargs, argsp, xdrres, resp, tout, port_ptr)
|
|
struct sockaddr_in *addr;
|
|
u_long prog, vers, proc;
|
|
xdrproc_t xdrargs, xdrres;
|
|
caddr_t argsp, resp;
|
|
struct timeval tout;
|
|
u_long *port_ptr;
|
|
{
|
|
int socket = -1;
|
|
register CLIENT *client;
|
|
struct rmtcallargs a;
|
|
struct rmtcallres r;
|
|
enum clnt_stat stat;
|
|
|
|
addr->sin_port = htons(PMAPPORT);
|
|
client = clntudp_create(addr, PMAPPROG, PMAPVERS, timeout, &socket);
|
|
if (client != (CLIENT *)NULL) {
|
|
a.prog = prog;
|
|
a.vers = vers;
|
|
a.proc = proc;
|
|
a.args_ptr = argsp;
|
|
a.xdr_args = xdrargs;
|
|
r.port_ptr = port_ptr;
|
|
r.results_ptr = resp;
|
|
r.xdr_results = xdrres;
|
|
stat = CLNT_CALL(client, PMAPPROC_CALLIT, xdr_rmtcall_args, &a,
|
|
xdr_rmtcallres, &r, tout);
|
|
CLNT_DESTROY(client);
|
|
} else {
|
|
stat = RPC_FAILED;
|
|
}
|
|
if (socket != -1)
|
|
(void)_close(socket);
|
|
addr->sin_port = 0;
|
|
return (stat);
|
|
}
|
|
|
|
|
|
/*
|
|
* XDR remote call arguments
|
|
* written for XDR_ENCODE direction only
|
|
*/
|
|
bool_t
|
|
xdr_rmtcall_args(xdrs, cap)
|
|
register XDR *xdrs;
|
|
register struct rmtcallargs *cap;
|
|
{
|
|
u_int lenposition, argposition, position;
|
|
|
|
if (xdr_u_long(xdrs, &(cap->prog)) &&
|
|
xdr_u_long(xdrs, &(cap->vers)) &&
|
|
xdr_u_long(xdrs, &(cap->proc))) {
|
|
lenposition = XDR_GETPOS(xdrs);
|
|
if (! xdr_u_long(xdrs, &(cap->arglen)))
|
|
return (FALSE);
|
|
argposition = XDR_GETPOS(xdrs);
|
|
if (! (*(cap->xdr_args))(xdrs, cap->args_ptr))
|
|
return (FALSE);
|
|
position = XDR_GETPOS(xdrs);
|
|
cap->arglen = (u_long)position - (u_long)argposition;
|
|
XDR_SETPOS(xdrs, lenposition);
|
|
if (! xdr_u_long(xdrs, &(cap->arglen)))
|
|
return (FALSE);
|
|
XDR_SETPOS(xdrs, position);
|
|
return (TRUE);
|
|
}
|
|
return (FALSE);
|
|
}
|
|
|
|
/*
|
|
* XDR remote call results
|
|
* written for XDR_DECODE direction only
|
|
*/
|
|
bool_t
|
|
xdr_rmtcallres(xdrs, crp)
|
|
register XDR *xdrs;
|
|
register struct rmtcallres *crp;
|
|
{
|
|
caddr_t port_ptr;
|
|
|
|
port_ptr = (caddr_t)crp->port_ptr;
|
|
if (xdr_reference(xdrs, &port_ptr, sizeof (u_long),
|
|
xdr_u_long) && xdr_u_long(xdrs, &crp->resultslen)) {
|
|
crp->port_ptr = (u_long *)port_ptr;
|
|
return ((*(crp->xdr_results))(xdrs, crp->results_ptr));
|
|
}
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
/*
|
|
* The following is kludged-up support for simple rpc broadcasts.
|
|
* Someday a large, complicated system will replace these trivial
|
|
* routines which only support udp/ip .
|
|
*/
|
|
|
|
static int
|
|
getbroadcastnets(addrs, sock, buf)
|
|
struct in_addr *addrs;
|
|
int sock; /* any valid socket will do */
|
|
char *buf; /* why allocxate more when we can use existing... */
|
|
{
|
|
struct ifconf ifc;
|
|
struct ifreq ifreq, *ifr;
|
|
struct sockaddr_in *sin;
|
|
struct in_addr addr;
|
|
char *cp, *cplim;
|
|
int n, i = 0;
|
|
|
|
ifc.ifc_len = UDPMSGSIZE;
|
|
ifc.ifc_buf = buf;
|
|
if (_ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
|
|
perror("broadcast: ioctl (get interface configuration)");
|
|
return (0);
|
|
}
|
|
#define max(a, b) (a > b ? a : b)
|
|
#define size(p) max((p).sa_len, sizeof(p))
|
|
cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */
|
|
for (cp = buf; cp < cplim;
|
|
cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) {
|
|
ifr = (struct ifreq *)cp;
|
|
if (ifr->ifr_addr.sa_family != AF_INET)
|
|
continue;
|
|
memcpy(&ifreq, ifr, sizeof(ifreq));
|
|
if (_ioctl(sock, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
|
|
perror("broadcast: ioctl (get interface flags)");
|
|
continue;
|
|
}
|
|
if ((ifreq.ifr_flags & IFF_BROADCAST) &&
|
|
(ifreq.ifr_flags & IFF_UP)) {
|
|
sin = (struct sockaddr_in *)&ifr->ifr_addr;
|
|
#ifdef SIOCGIFBRDADDR /* 4.3BSD */
|
|
if (_ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) {
|
|
addr =
|
|
inet_makeaddr(inet_netof(sin->sin_addr),
|
|
INADDR_ANY);
|
|
} else {
|
|
addr = ((struct sockaddr_in*)
|
|
&ifreq.ifr_addr)->sin_addr;
|
|
}
|
|
#else /* 4.2 BSD */
|
|
addr = inet_makeaddr(inet_netof(sin->sin_addr),
|
|
INADDR_ANY);
|
|
#endif
|
|
for (n=i-1; n>=0; n--) {
|
|
if (addr.s_addr == addrs[n].s_addr)
|
|
break;
|
|
}
|
|
if (n<0) {
|
|
addrs[i++] = addr;
|
|
}
|
|
}
|
|
}
|
|
return (i);
|
|
}
|
|
|
|
typedef bool_t (*resultproc_t)();
|
|
|
|
enum clnt_stat
|
|
clnt_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, eachresult)
|
|
u_long prog; /* program number */
|
|
u_long vers; /* version number */
|
|
u_long proc; /* procedure number */
|
|
xdrproc_t xargs; /* xdr routine for args */
|
|
caddr_t argsp; /* pointer to args */
|
|
xdrproc_t xresults; /* xdr routine for results */
|
|
caddr_t resultsp; /* pointer to results */
|
|
resultproc_t eachresult; /* call with each result obtained */
|
|
{
|
|
enum clnt_stat stat;
|
|
AUTH *unix_auth = authunix_create_default();
|
|
XDR xdr_stream;
|
|
register XDR *xdrs = &xdr_stream;
|
|
int outlen, inlen, fromlen, nets;
|
|
register int sock;
|
|
int on = 1;
|
|
fd_set *fds, readfds;
|
|
register int i;
|
|
bool_t done = FALSE;
|
|
register u_long xid;
|
|
u_long port;
|
|
struct in_addr addrs[20];
|
|
struct sockaddr_in baddr, raddr; /* broadcast and response addresses */
|
|
struct rmtcallargs a;
|
|
struct rmtcallres r;
|
|
struct rpc_msg msg;
|
|
struct timeval t, tv;
|
|
char outbuf[MAX_BROADCAST_SIZE], inbuf[UDPMSGSIZE];
|
|
static u_int32_t disrupt;
|
|
|
|
if (disrupt == 0)
|
|
disrupt = (u_int32_t)(long)resultsp;
|
|
|
|
/*
|
|
* initialization: create a socket, a broadcast address, and
|
|
* preserialize the arguments into a send buffer.
|
|
*/
|
|
if ((sock = _socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
|
|
perror("Cannot create socket for broadcast rpc");
|
|
stat = RPC_CANTSEND;
|
|
goto done_broad;
|
|
}
|
|
#ifdef SO_BROADCAST
|
|
if (_setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
|
|
perror("Cannot set socket option SO_BROADCAST");
|
|
stat = RPC_CANTSEND;
|
|
goto done_broad;
|
|
}
|
|
#endif /* def SO_BROADCAST */
|
|
if (sock + 1 > FD_SETSIZE) {
|
|
int bytes = howmany(sock + 1, NFDBITS) * sizeof(fd_mask);
|
|
fds = (fd_set *)malloc(bytes);
|
|
if (fds == NULL) {
|
|
stat = RPC_CANTSEND;
|
|
goto done_broad;
|
|
}
|
|
memset(fds, 0, bytes);
|
|
} else {
|
|
fds = &readfds;
|
|
FD_ZERO(fds);
|
|
}
|
|
|
|
nets = getbroadcastnets(addrs, sock, inbuf);
|
|
memset(&baddr, 0, sizeof (baddr));
|
|
baddr.sin_len = sizeof(struct sockaddr_in);
|
|
baddr.sin_family = AF_INET;
|
|
baddr.sin_port = htons(PMAPPORT);
|
|
baddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
(void)gettimeofday(&t, (struct timezone *)0);
|
|
msg.rm_xid = xid = (++disrupt) ^ getpid() ^ t.tv_sec ^ t.tv_usec;
|
|
t.tv_usec = 0;
|
|
msg.rm_direction = CALL;
|
|
msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
|
|
msg.rm_call.cb_prog = PMAPPROG;
|
|
msg.rm_call.cb_vers = PMAPVERS;
|
|
msg.rm_call.cb_proc = PMAPPROC_CALLIT;
|
|
msg.rm_call.cb_cred = unix_auth->ah_cred;
|
|
msg.rm_call.cb_verf = unix_auth->ah_verf;
|
|
a.prog = prog;
|
|
a.vers = vers;
|
|
a.proc = proc;
|
|
a.xdr_args = xargs;
|
|
a.args_ptr = argsp;
|
|
r.port_ptr = &port;
|
|
r.xdr_results = xresults;
|
|
r.results_ptr = resultsp;
|
|
xdrmem_create(xdrs, outbuf, MAX_BROADCAST_SIZE, XDR_ENCODE);
|
|
if ((! xdr_callmsg(xdrs, &msg)) || (! xdr_rmtcall_args(xdrs, &a))) {
|
|
stat = RPC_CANTENCODEARGS;
|
|
goto done_broad;
|
|
}
|
|
outlen = (int)xdr_getpos(xdrs);
|
|
xdr_destroy(xdrs);
|
|
/*
|
|
* Basic loop: broadcast a packet and wait a while for response(s).
|
|
* The response timeout grows larger per iteration.
|
|
*
|
|
* XXX This will loop about 5 times the stop. If there are
|
|
* lots of signals being received by the process it will quit
|
|
* send them all in one quick burst, not paying attention to
|
|
* the intended function of sending them slowly over half a
|
|
* minute or so
|
|
*/
|
|
for (t.tv_sec = 4; t.tv_sec <= 14; t.tv_sec += 2) {
|
|
for (i = 0; i < nets; i++) {
|
|
baddr.sin_addr = addrs[i];
|
|
if (_sendto(sock, outbuf, outlen, 0,
|
|
(struct sockaddr *)&baddr,
|
|
sizeof (struct sockaddr)) != outlen) {
|
|
perror("Cannot send broadcast packet");
|
|
stat = RPC_CANTSEND;
|
|
goto done_broad;
|
|
}
|
|
}
|
|
if (eachresult == NULL) {
|
|
stat = RPC_SUCCESS;
|
|
goto done_broad;
|
|
}
|
|
recv_again:
|
|
msg.acpted_rply.ar_verf = _null_auth;
|
|
msg.acpted_rply.ar_results.where = (caddr_t)&r;
|
|
msg.acpted_rply.ar_results.proc = xdr_rmtcallres;
|
|
/* XXX we know the other bits are still clear */
|
|
FD_SET(sock, fds);
|
|
tv = t; /* for _select() that copies back */
|
|
switch (_select(sock + 1, fds, NULL, NULL, &tv)) {
|
|
|
|
case 0: /* timed out */
|
|
stat = RPC_TIMEDOUT;
|
|
continue;
|
|
|
|
case -1: /* some kind of error */
|
|
if (errno == EINTR)
|
|
goto recv_again;
|
|
perror("Broadcast select problem");
|
|
stat = RPC_CANTRECV;
|
|
goto done_broad;
|
|
|
|
} /* end of select results switch */
|
|
try_again:
|
|
fromlen = sizeof(struct sockaddr);
|
|
inlen = _recvfrom(sock, inbuf, UDPMSGSIZE, 0,
|
|
(struct sockaddr *)&raddr, &fromlen);
|
|
if (inlen < 0) {
|
|
if (errno == EINTR)
|
|
goto try_again;
|
|
perror("Cannot receive reply to broadcast");
|
|
stat = RPC_CANTRECV;
|
|
goto done_broad;
|
|
}
|
|
if (inlen < sizeof(u_int32_t))
|
|
goto recv_again;
|
|
/*
|
|
* see if reply transaction id matches sent id.
|
|
* If so, decode the results.
|
|
*/
|
|
xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE);
|
|
if (xdr_replymsg(xdrs, &msg)) {
|
|
if ((msg.rm_xid == xid) &&
|
|
(msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
|
|
(msg.acpted_rply.ar_stat == SUCCESS)) {
|
|
raddr.sin_port = htons((u_short)port);
|
|
done = (*eachresult)(resultsp, &raddr);
|
|
}
|
|
/* otherwise, we just ignore the errors ... */
|
|
}
|
|
xdrs->x_op = XDR_FREE;
|
|
msg.acpted_rply.ar_results.proc = xdr_void;
|
|
(void)xdr_replymsg(xdrs, &msg);
|
|
(void)(*xresults)(xdrs, resultsp);
|
|
xdr_destroy(xdrs);
|
|
if (done) {
|
|
stat = RPC_SUCCESS;
|
|
goto done_broad;
|
|
} else {
|
|
goto recv_again;
|
|
}
|
|
}
|
|
done_broad:
|
|
if (fds != &readfds)
|
|
free(fds);
|
|
if (sock >= 0)
|
|
(void)_close(sock);
|
|
AUTH_DESTROY(unix_auth);
|
|
return (stat);
|
|
}
|
|
|