+++ /dev/null
-/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
- * Reserved. This file contains Original Code and/or Modifications of
- * Original Code as defined in and that are subject to the Apple Public
- * Source License Version 1.1 (the "License"). You may not use this file
- * except in compliance with the License. Please obtain a copy of the
- * License at http://www.apple.com/publicsource and read it before using
- * this file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-/*
- * multi_call: send out multiple call messages, wait for first reply
- * Copyright (C) 1991 by NeXT, Inc.
- */
-#include <rpc/rpc.h>
-#include <rpc/pmap_prot.h>
-#include <sys/socket.h>
-#include <syslog.h>
-#include <sys/param.h>
-#include <arpa/inet.h>
-#include <string.h>
-#include <unistd.h>
-
-#ifdef NETINFOD
-# include "socket_lock.h"
-# include "clib.h"
-# define multi_call _multi_call
-#else
-# define socket_lock()
-# define socket_unlock()
-# include "clib.h"
-#endif
-
-
-#define NRETRIES 5
-#define USECS_PER_SEC 1000000
-
-
-/*
- * Wrapper for gethostname() syscall
- */
-static char *
-get_hostname(void)
-{
- int len;
- static char hostname[MAXHOSTNAMELEN + 1];
-
- len = gethostname(hostname, sizeof(hostname));
- if (len < 0) {
- hostname[0] = 0;
- } else {
- hostname[len] = 0;
- }
- return (hostname);
-}
-
-
-/*
- * Encode a call message
- */
-static int
-encodemsg(
- char *buf,
- int buflen,
- struct rpc_msg *call,
- unsigned prognum,
- unsigned versnum,
- unsigned procnum,
- xdrproc_t xdr_args,
- void *arg
- )
-{
- XDR xdr;
- unsigned size;
- unsigned pos;
-
- xdrmem_create(&xdr, buf, buflen, XDR_ENCODE);
- if (!xdr_callmsg(&xdr, call) ||
- !xdr_u_int(&xdr, &prognum) ||
- !xdr_u_int(&xdr, &versnum) ||
- !xdr_u_int(&xdr, &procnum)) {
- return (0);
- }
- pos = xdr_getpos(&xdr);
- xdr_setpos(&xdr, pos + BYTES_PER_XDR_UNIT);
- if (!(*xdr_args)(&xdr, arg)) {
- return (0);
- }
- size = xdr_getpos(&xdr) - pos;
- xdr_setpos(&xdr, pos);
- if (!xdr_u_int(&xdr, &size)) {
- return (0);
- }
- return (pos + BYTES_PER_XDR_UNIT + size);
-}
-
-/*
- * Decode a reply message
- */
-static int
-decodemsg(
- XDR *xdr,
- xdrproc_t xdr_res,
- void *res
- )
-{
- unsigned port;
- unsigned len;
- long *buf;
- XDR bufxdr;
-
- if (!xdr_u_int(xdr, &port) ||
- !xdr_u_int(xdr, &len) ||
- !(buf = (long *)xdr_inline(xdr, len))) {
- return (0);
- }
- xdrmem_create(&bufxdr, (char *)buf, len * BYTES_PER_XDR_UNIT,
- XDR_DECODE);
- if (!(*xdr_res)(&bufxdr, res)) {
- return (0);
- }
- return (1);
-
-}
-
-/*
- * Do the real work
- */
-enum clnt_stat
-multi_call(
- unsigned naddrs,
- struct in_addr *addrs,
- u_long prognum,
- u_long versnum,
- u_long procnum,
- xdrproc_t xdr_args,
- void *argsvec,
- unsigned argsize,
- xdrproc_t xdr_res,
- void *res,
- int (*eachresult)(void *, struct sockaddr_in *, int),
- int timeout
- )
-{
- struct authunix_parms aup;
- char credbuf[MAX_AUTH_BYTES];
- struct opaque_auth cred;
- struct opaque_auth verf;
- int gids[NGROUPS];
- int s;
- struct timeval tv;
- struct timeval subtimeout;
- unsigned long long utimeout;
- int callno;
- int serverno;
- struct rpc_msg call;
- struct rpc_msg reply;
- struct sockaddr_in sin;
- struct sockaddr_in from;
- int fromsize;
- char buf[UDPMSGSIZE];
- int buflen;
- unsigned trans_id;
- int dtablesize = getdtablesize();
- XDR xdr;
- int sendlen;
- fd_set fds;
-
- /*
- * Fill in Unix auth stuff
- */
- aup.aup_time = time(0);
- aup.aup_machname = get_hostname();
- aup.aup_uid = getuid();
- aup.aup_gid = getgid();
- aup.aup_gids = gids;
- aup.aup_len = getgroups(NGROUPS, aup.aup_gids);
-
- /*
- * Encode unix auth
- */
- xdrmem_create(&xdr, credbuf, sizeof(credbuf), XDR_ENCODE);
- if (!xdr_authunix_parms(&xdr, &aup)) {
- return (RPC_CANTENCODEARGS);
- }
- cred.oa_flavor = AUTH_UNIX;
- cred.oa_base = credbuf;
- cred.oa_length = xdr_getpos(&xdr);
-
- verf.oa_flavor = AUTH_NULL;
- verf.oa_length = 0;
-
- /*
- * Set up call header information
- */
- trans_id = time(0) ^ getpid();
- call.rm_xid = trans_id;
- call.rm_direction = CALL;
- call.rm_call.cb_rpcvers = 2;
- call.rm_call.cb_prog = PMAPPROG;
- call.rm_call.cb_vers = PMAPVERS;
- call.rm_call.cb_proc = PMAPPROC_CALLIT;
- call.rm_call.cb_cred = cred;
- call.rm_call.cb_verf = verf;
-
-
- /*
- * Open socket
- */
- socket_lock();
- s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- socket_unlock();
- if (s < 0) {
- syslog(LOG_ERR, "multi_call: socket: %m");
- return (RPC_FAILED);
- }
-
- /*
- * Init timeouts
- */
- utimeout = ((unsigned long long) timeout) * USECS_PER_SEC;
- subtimeout.tv_sec = (utimeout >> NRETRIES) / USECS_PER_SEC;
- subtimeout.tv_usec = (utimeout >> NRETRIES) % USECS_PER_SEC;
- tv = subtimeout;
-
- /*
- * Init address info
- */
- sin.sin_family = AF_INET;
- sin.sin_port = htons(PMAPPORT);
- bzero(sin.sin_zero, sizeof(sin.sin_zero));
-
- for (callno = 0; callno <= NRETRIES; callno++) {
- /*
- * Send a call message to each host with the appropriate args
- */
- for (serverno = 0; serverno < naddrs; serverno++) {
- call.rm_xid = trans_id + serverno;
- buflen = encodemsg(buf, sizeof(buf), &call,
- prognum, versnum, procnum,
- xdr_args, (argsvec +
- (serverno * argsize)));
- if (buflen == 0) {
- /*
- * Encode failed
- */
- continue;
- }
- sin.sin_addr = addrs[serverno];
- sendlen = sendto(s, buf, buflen, 0,
- (struct sockaddr *)&sin, sizeof(sin));
- if (sendlen != buflen) {
- syslog(LOG_ERR,
- "Cannot send multicall packet to %s: %m",
- inet_ntoa(addrs[serverno]));
- }
- }
-
- /*
- * Double the timeout from previous timeout, if necessary
- */
- if (callno > 1) {
- tv.tv_sec *= 2;
- tv.tv_usec *= 2;
- if (tv.tv_usec >= USECS_PER_SEC) {
- tv.tv_usec -= USECS_PER_SEC;
- tv.tv_sec++;
- }
- }
-
-
-#ifdef NETINFOD
- /*
- * Check for cancel by user
- */
- if (alert_aborted()) {
- socket_lock();
- close(s);
- socket_unlock();
- return (RPC_FAILED);
- }
-#endif
- /*
- * Wait for reply
- */
- FD_ZERO(&fds);
- FD_SET(s, &fds);
- switch (select(dtablesize, &fds, NULL, NULL, &tv)) {
- case -1:
- syslog(LOG_ERR, "select failure: %m");
- continue;
- case 0:
- continue;
- default:
- break;
- }
-
- /*
- * Receive packet
- */
- fromsize = sizeof(from);
- buflen = recvfrom(s, buf, sizeof(buf), 0,
- (struct sockaddr *)&from, &fromsize);
- if (buflen < 0) {
- continue;
- }
-
- /*
- * Decode packet and if no errors, call eachresult
- */
- xdrmem_create(&xdr, buf, buflen, XDR_DECODE);
- reply.rm_reply.rp_acpt.ar_results.proc = xdr_void;
- reply.rm_reply.rp_acpt.ar_results.where = NULL;
- if (xdr_replymsg(&xdr, &reply) &&
- (reply.rm_xid >= trans_id) &&
- (reply.rm_xid < trans_id + naddrs) &&
- (reply.rm_reply.rp_stat == MSG_ACCEPTED) &&
- (reply.acpted_rply.ar_stat == SUCCESS) &&
- decodemsg(&xdr, xdr_res, res)) {
- if ((*eachresult)(res, &from,
- reply.rm_xid - trans_id)) {
- xdr_free(xdr_res, res);
- socket_lock();
- close(s);
- socket_unlock();
- return (RPC_SUCCESS);
- }
- }
- xdr_free(xdr_res, res);
- }
- socket_lock();
- close(s);
- socket_unlock();
- return (RPC_TIMEDOUT);
-}
-
-
-
-