]>
git.saurik.com Git - apple/libinfo.git/blob - netinfo.subproj/multi_call.c
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * multi_call: send out multiple call messages, wait for first reply
27 * Copyright (C) 1991 by NeXT, Inc.
30 #include <rpc/pmap_prot.h>
31 #include <sys/socket.h>
33 #include <sys/param.h>
34 #include <arpa/inet.h>
39 # include "socket_lock.h"
41 # define multi_call _multi_call
43 # define socket_lock()
44 # define socket_unlock()
50 #define USECS_PER_SEC 1000000
54 * Wrapper for gethostname() syscall
60 static char hostname
[MAXHOSTNAMELEN
+ 1];
62 len
= gethostname(hostname
, sizeof(hostname
));
73 * Encode a call message
91 xdrmem_create(&xdr
, buf
, buflen
, XDR_ENCODE
);
92 if (!xdr_callmsg(&xdr
, call
) ||
93 !xdr_u_int(&xdr
, &prognum
) ||
94 !xdr_u_int(&xdr
, &versnum
) ||
95 !xdr_u_int(&xdr
, &procnum
)) {
98 pos
= xdr_getpos(&xdr
);
99 xdr_setpos(&xdr
, pos
+ BYTES_PER_XDR_UNIT
);
100 if (!(*xdr_args
)(&xdr
, arg
)) {
103 size
= xdr_getpos(&xdr
) - pos
;
104 xdr_setpos(&xdr
, pos
);
105 if (!xdr_u_int(&xdr
, &size
)) {
108 return (pos
+ BYTES_PER_XDR_UNIT
+ size
);
112 * Decode a reply message
126 if (!xdr_u_int(xdr
, &port
) ||
127 !xdr_u_int(xdr
, &len
) ||
128 !(buf
= (long *)xdr_inline(xdr
, len
))) {
131 xdrmem_create(&bufxdr
, (char *)buf
, len
* BYTES_PER_XDR_UNIT
,
133 if (!(*xdr_res
)(&bufxdr
, res
)) {
146 struct in_addr
*addrs
,
155 int (*eachresult
)(void *, struct sockaddr_in
*, int),
159 struct authunix_parms aup
;
160 char credbuf
[MAX_AUTH_BYTES
];
161 struct opaque_auth cred
;
162 struct opaque_auth verf
;
166 struct timeval subtimeout
;
167 unsigned long long utimeout
;
171 struct rpc_msg reply
;
172 struct sockaddr_in sin
;
173 struct sockaddr_in from
;
175 char buf
[UDPMSGSIZE
];
178 int dtablesize
= getdtablesize();
184 * Fill in Unix auth stuff
186 aup
.aup_time
= time(0);
187 aup
.aup_machname
= get_hostname();
188 aup
.aup_uid
= getuid();
189 aup
.aup_gid
= getgid();
191 aup
.aup_len
= getgroups(NGROUPS
, aup
.aup_gids
);
196 xdrmem_create(&xdr
, credbuf
, sizeof(credbuf
), XDR_ENCODE
);
197 if (!xdr_authunix_parms(&xdr
, &aup
)) {
198 return (RPC_CANTENCODEARGS
);
200 cred
.oa_flavor
= AUTH_UNIX
;
201 cred
.oa_base
= credbuf
;
202 cred
.oa_length
= xdr_getpos(&xdr
);
204 verf
.oa_flavor
= AUTH_NULL
;
208 * Set up call header information
210 trans_id
= time(0) ^ getpid();
211 call
.rm_xid
= trans_id
;
212 call
.rm_direction
= CALL
;
213 call
.rm_call
.cb_rpcvers
= 2;
214 call
.rm_call
.cb_prog
= PMAPPROG
;
215 call
.rm_call
.cb_vers
= PMAPVERS
;
216 call
.rm_call
.cb_proc
= PMAPPROC_CALLIT
;
217 call
.rm_call
.cb_cred
= cred
;
218 call
.rm_call
.cb_verf
= verf
;
225 s
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
228 syslog(LOG_ERR
, "multi_call: socket: %m");
235 utimeout
= ((unsigned long long) timeout
) * USECS_PER_SEC
;
236 subtimeout
.tv_sec
= (utimeout
>> NRETRIES
) / USECS_PER_SEC
;
237 subtimeout
.tv_usec
= (utimeout
>> NRETRIES
) % USECS_PER_SEC
;
243 sin
.sin_family
= AF_INET
;
244 sin
.sin_port
= htons(PMAPPORT
);
245 bzero(sin
.sin_zero
, sizeof(sin
.sin_zero
));
247 for (callno
= 0; callno
<= NRETRIES
; callno
++) {
249 * Send a call message to each host with the appropriate args
251 for (serverno
= 0; serverno
< naddrs
; serverno
++) {
252 call
.rm_xid
= trans_id
+ serverno
;
253 buflen
= encodemsg(buf
, sizeof(buf
), &call
,
254 prognum
, versnum
, procnum
,
256 (serverno
* argsize
)));
263 sin
.sin_addr
= addrs
[serverno
];
264 sendlen
= sendto(s
, buf
, buflen
, 0,
265 (struct sockaddr
*)&sin
, sizeof(sin
));
266 if (sendlen
!= buflen
) {
268 "Cannot send multicall packet to %s: %m",
269 inet_ntoa(addrs
[serverno
]));
274 * Double the timeout from previous timeout, if necessary
279 if (tv
.tv_usec
>= USECS_PER_SEC
) {
280 tv
.tv_usec
-= USECS_PER_SEC
;
288 * Check for cancel by user
290 if (alert_aborted()) {
302 switch (select(dtablesize
, &fds
, NULL
, NULL
, &tv
)) {
304 syslog(LOG_ERR
, "select failure: %m");
315 fromsize
= sizeof(from
);
316 buflen
= recvfrom(s
, buf
, sizeof(buf
), 0,
317 (struct sockaddr
*)&from
, &fromsize
);
323 * Decode packet and if no errors, call eachresult
325 xdrmem_create(&xdr
, buf
, buflen
, XDR_DECODE
);
326 reply
.rm_reply
.rp_acpt
.ar_results
.proc
= xdr_void
;
327 reply
.rm_reply
.rp_acpt
.ar_results
.where
= NULL
;
328 if (xdr_replymsg(&xdr
, &reply
) &&
329 (reply
.rm_xid
>= trans_id
) &&
330 (reply
.rm_xid
< trans_id
+ naddrs
) &&
331 (reply
.rm_reply
.rp_stat
== MSG_ACCEPTED
) &&
332 (reply
.acpted_rply
.ar_stat
== SUCCESS
) &&
333 decodemsg(&xdr
, xdr_res
, res
)) {
334 if ((*eachresult
)(res
, &from
,
335 reply
.rm_xid
- trans_id
)) {
336 xdr_free(xdr_res
, res
);
340 return (RPC_SUCCESS
);
343 xdr_free(xdr_res
, res
);
348 return (RPC_TIMEDOUT
);