]>
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 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
25 * multi_call: send out multiple call messages, wait for first reply
26 * Copyright (C) 1991 by NeXT, Inc.
29 #include <rpc/pmap_prot.h>
30 #include <sys/socket.h>
32 #include <sys/param.h>
33 #include <arpa/inet.h>
38 # include "socket_lock.h"
40 # define multi_call _multi_call
42 # define socket_lock()
43 # define socket_unlock()
49 #define USECS_PER_SEC 1000000
53 * Wrapper for gethostname() syscall
59 static char hostname
[MAXHOSTNAMELEN
+ 1];
61 len
= gethostname(hostname
, sizeof(hostname
));
72 * Encode a call message
90 xdrmem_create(&xdr
, buf
, buflen
, XDR_ENCODE
);
91 if (!xdr_callmsg(&xdr
, call
) ||
92 !xdr_u_int(&xdr
, &prognum
) ||
93 !xdr_u_int(&xdr
, &versnum
) ||
94 !xdr_u_int(&xdr
, &procnum
)) {
97 pos
= xdr_getpos(&xdr
);
98 xdr_setpos(&xdr
, pos
+ BYTES_PER_XDR_UNIT
);
99 if (!(*xdr_args
)(&xdr
, arg
)) {
102 size
= xdr_getpos(&xdr
) - pos
;
103 xdr_setpos(&xdr
, pos
);
104 if (!xdr_u_int(&xdr
, &size
)) {
107 return (pos
+ BYTES_PER_XDR_UNIT
+ size
);
111 * Decode a reply message
125 if (!xdr_u_int(xdr
, &port
) ||
126 !xdr_u_int(xdr
, &len
) ||
127 !(buf
= xdr_inline(xdr
, len
))) {
130 xdrmem_create(&bufxdr
, (char *)buf
, len
* BYTES_PER_XDR_UNIT
,
132 if (!(*xdr_res
)(&bufxdr
, res
)) {
145 struct in_addr
*addrs
,
154 int (*eachresult
)(void *, struct sockaddr_in
*, int),
158 struct authunix_parms aup
;
159 char credbuf
[MAX_AUTH_BYTES
];
160 struct opaque_auth cred
;
161 struct opaque_auth verf
;
165 struct timeval subtimeout
;
166 unsigned long long utimeout
;
170 struct rpc_msg reply
;
171 struct sockaddr_in sin
;
172 struct sockaddr_in from
;
174 char buf
[UDPMSGSIZE
];
177 int dtablesize
= getdtablesize();
183 * Fill in Unix auth stuff
185 aup
.aup_time
= time(0);
186 aup
.aup_machname
= get_hostname();
187 aup
.aup_uid
= getuid();
188 aup
.aup_gid
= getgid();
190 aup
.aup_len
= getgroups(NGROUPS
, aup
.aup_gids
);
195 xdrmem_create(&xdr
, credbuf
, sizeof(credbuf
), XDR_ENCODE
);
196 if (!xdr_authunix_parms(&xdr
, &aup
)) {
197 return (RPC_CANTENCODEARGS
);
199 cred
.oa_flavor
= AUTH_UNIX
;
200 cred
.oa_base
= credbuf
;
201 cred
.oa_length
= xdr_getpos(&xdr
);
203 verf
.oa_flavor
= AUTH_NULL
;
207 * Set up call header information
209 trans_id
= time(0) ^ getpid();
210 call
.rm_xid
= trans_id
;
211 call
.rm_direction
= CALL
;
212 call
.rm_call
.cb_rpcvers
= 2;
213 call
.rm_call
.cb_prog
= PMAPPROG
;
214 call
.rm_call
.cb_vers
= PMAPVERS
;
215 call
.rm_call
.cb_proc
= PMAPPROC_CALLIT
;
216 call
.rm_call
.cb_cred
= cred
;
217 call
.rm_call
.cb_verf
= verf
;
224 s
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
227 syslog(LOG_ERR
, "multi_call: socket: %m");
234 utimeout
= ((unsigned long long) timeout
) * USECS_PER_SEC
;
235 subtimeout
.tv_sec
= (utimeout
>> NRETRIES
) / USECS_PER_SEC
;
236 subtimeout
.tv_usec
= (utimeout
>> NRETRIES
) % USECS_PER_SEC
;
242 sin
.sin_family
= AF_INET
;
243 sin
.sin_port
= htons(PMAPPORT
);
244 bzero(sin
.sin_zero
, sizeof(sin
.sin_zero
));
246 for (callno
= 0; callno
<= NRETRIES
; callno
++) {
248 * Send a call message to each host with the appropriate args
250 for (serverno
= 0; serverno
< naddrs
; serverno
++) {
251 call
.rm_xid
= trans_id
+ serverno
;
252 buflen
= encodemsg(buf
, sizeof(buf
), &call
,
253 prognum
, versnum
, procnum
,
255 (serverno
* argsize
)));
262 sin
.sin_addr
= addrs
[serverno
];
263 sendlen
= sendto(s
, buf
, buflen
, 0,
264 (struct sockaddr
*)&sin
, sizeof(sin
));
265 if (sendlen
!= buflen
) {
267 "Cannot send multicall packet to %s: %m",
268 inet_ntoa(addrs
[serverno
]));
273 * Double the timeout from previous timeout, if necessary
278 if (tv
.tv_usec
>= USECS_PER_SEC
) {
279 tv
.tv_usec
-= USECS_PER_SEC
;
287 * Check for cancel by user
289 if (alert_aborted()) {
301 switch (select(dtablesize
, &fds
, NULL
, NULL
, &tv
)) {
303 syslog(LOG_ERR
, "select failure: %m");
314 fromsize
= sizeof(from
);
315 buflen
= recvfrom(s
, buf
, sizeof(buf
), 0,
316 (struct sockaddr
*)&from
, &fromsize
);
322 * Decode packet and if no errors, call eachresult
324 xdrmem_create(&xdr
, buf
, buflen
, XDR_DECODE
);
325 reply
.rm_reply
.rp_acpt
.ar_results
.proc
= xdr_void
;
326 reply
.rm_reply
.rp_acpt
.ar_results
.where
= NULL
;
327 if (xdr_replymsg(&xdr
, &reply
) &&
328 (reply
.rm_xid
>= trans_id
) &&
329 (reply
.rm_xid
< trans_id
+ naddrs
) &&
330 (reply
.rm_reply
.rp_stat
== MSG_ACCEPTED
) &&
331 (reply
.acpted_rply
.ar_stat
== SUCCESS
) &&
332 decodemsg(&xdr
, xdr_res
, res
)) {
333 if ((*eachresult
)(res
, &from
,
334 reply
.rm_xid
- trans_id
)) {
335 xdr_free(xdr_res
, res
);
339 return (RPC_SUCCESS
);
342 xdr_free(xdr_res
, res
);
347 return (RPC_TIMEDOUT
);