mirror of
git://sourceware.org/git/glibc.git
synced 2024-11-27 03:41:23 +08:00
b20e47cb14
* sysdeps/unix/bsd/pause.c: Moved to sysdeps/unix/common/pause.c. Mon Mar 4 20:17:28 1996 David Mosberger-Tang <davidm@azstarnet.com> * sysdeps/unix/sysv/linux/adjtime.c: Use INT_MAX instead of LONG_MAX. * sysdeps/unix/sysv/Makefile (sysdep_routines): Don't add s_getdents. * sysdeps/unix/sysv/linux/Makefile (sysdep_routines): Don't add mount, umount. * sysdeps/alpha/__math.h (atan, cabs): New functions. * sysdeps/unix/sysv/linux/alpha/sigsuspend.S: new file (syscall expects set-value, not pointer to it). Sun Feb 25 22:36:10 1996 David Mosberger-Tang <davidm@azstarnet.com> * sysdeps/unix/sysv/linux/alpha/profil-counter.h: New file. * gmon/gmon.c (__bb_head): new variable. (write_hist, write_call_graph, write_bb_counts): new functions. (_mcleanup): modified to call above functions instead of directly writing out gmon.out. * gmon/sys/gmon.h (struct __bb): New type. (struct gmonhdr): Type removed. (struct gmonparam): New member `log_hashfraction'. (GMONVERSION): Macro removed. * gmon/sys/gmon_out.h, gmon/bb_exit_func.c, sysdeps/generic/bb_init_func.c, sysdeps/alpha/bb_init_func.S: new files. * gmon/Makefile (headers): Add sys/gmon_out.h. (routines): Add bb_init_func, bb_exit_func. * gmon/mcount.c: Avoid integer division. Wed Feb 21 23:56:41 1996 David Mosberger-Tang <davidm@azstarnet.com> * sysdeps/alpha/setjmp.S: switched order in which sp and fp are passed to match what __sigsetjmp_aux() expects. Tue Feb 20 11:33:46 1996 David Mosberger-Tang <davidm@azstarnet.com> * sysdeps/unix/sysv/linux/alpha/syscalls.list (select, bind, connect, getpeername, getsockname, listen, recv, recvfrom, recvmsg, send, sendmsg, sendto, setsockopt, shutdown, socketpair): added to override same-name assembly file in the parent directory. * stdlib/stdlib.h: add include of sys/types.h in front of random etc declarations to ensure int32_t is declared. * stdlib/random.c, stdlib/random_r.c: replaced "long int" by int32_t where 32 bit integers are required. Also change LONG_MAX into 0x7fffffff since the intent is to turn off the sign bit in a 32 bit integer. * time/offtime.c (__offtime): Use Paul Eggert's code to deal with very large values for "days" (e.g., 64 bit values). Mon Feb 19 22:22:12 1996 David Mosberger-Tang <davidm@azstarnet.com> * stdlib/stdlib.h (__random, __random_r, random_r, struct random_data): use int32_t instead of `long int'. Sat Feb 17 11:29:29 1996 David Mosberger-Tang <davidm@azstarnet.com> * sysdeps/unix/sysv/linux/alpha/ioperm.c: new file. * sysdeps/alpha/ffs.S: new file. * sysdeps/alpha/fabs.c: File removed. * time/tzfile.c (__tzfile_read): counter variable is i, *not* num_transitions! * time/offtime.c: make capable of dealing with very large (64 bit) time_t values. Use old algorithm until a year is reached that is an integer multiple of 400, then use DAYS_PER_400_YEARS to do the remainder in a single division. * sysdeps/generic/ffs.c (ffs): fix variable declarations to be unsigned int, not unsigned long. * string/test-ffs.c (main): add test case with all upper bits set. * stdlib/tst-strtol.c: add tests cases for machines where sizeof(long)==8. * stdlib/testrand.c (main): disallow rand() to return negative integers. * stdlib/testmb.c (main): fix format to use %lx instead of %x. * stdlib/stdlib.h: on 64 bit machines, declare struct random_data, __random(), __random_r, and random_r to return "int" instead of "long int". * stdlib/random_r.c: 64 bit machines use "int" instead of "long int". Similarly, use INT_MAX instead of LONG_MAX. * stdlib/random.c: on 64 bit machines, randtbl[] and __random[] need to operate on "int" instead of "long int". * locale/locfile-hash.c (compute_hashval): make shifted constant a long to avoid loosing bits on 64 bit machines. * dirent/tst-seekdir.c (main): fix confusing comment; print a line to mark point where directory is rewound. Fri Feb 16 15:01:49 1996 David Mosberger-Tang <davidm@azstarnet.com> * time/strftime.c (strftime): any hour > 11 is PM (not > 12!). Wed Feb 14 00:21:17 1996 David Mosberger-Tang <davidm@azstarnet.com> * sysdeps/unix/sysv/linux/alpha/Makefile, sysdeps/unix/sysv/linux/alpha/brk.S, sysdeps/unix/sysv/linux/alpha/fpu_control.c, sysdeps/unix/sysv/linux/alpha/fpu_control.h, sysdeps/unix/sysv/linux/alpha/ieee_get_fp_control.S, sysdeps/unix/sysv/linux/alpha/ieee_set_fp_control.S, sysdeps/unix/sysv/linux/alpha/pipe.S, sysdeps/unix/sysv/linux/alpha/setfpucw.c, sysdeps/unix/sysv/linux/alpha/sigprocmask.c, sysdeps/unix/sysv/linux/alpha/speed.c, sysdeps/unix/sysv/linux/alpha/start.S, sysdeps/unix/sysv/linux/alpha/syscall.S, sysdeps/unix/sysv/linux/alpha/syscalls.list, sysdeps/unix/sysv/linux/alpha/alpha/regdef.h, sysdeps/unix/sysv/linux/alpha/sysdep.S, sysdeps/unix/sysv/linux/alpha/sysdep.h: New files. * sysdeps/alpha/setjmp_aux.c (__sigsetjmp_aux): restore return address register before returning (gcc 2.7.1 doesn't do it, presumably because $26 is declared as a global variable). * sysdeps/unix/sysv/linux/sys/mman.h: msync was missing "flags" argument. * sysdeps/unix/alarm.c (alarm): do roundup using test & increment instead of multiplication. * sysdeps/posix/sleep.c (sleep): initialize sa_mask to mask of currently blocked signals instead of the empty mask to ensure that execution of alarm handler occurs with none of the currently blocked signals enabled. * sysdeps/unix/alpha/sysdep.h: new file (adapted from OSF/1 version). * sysdeps/unix/bsd/osf/alpha/sysdep.h: include sysdeps/unix/alpha/sysdep.h and removed definitions now in that file. * sysdeps/alpha/divrem.S, sysdeps/alpha/htonl.S, sysdeps/alpha/htons.S, sysdeps/alpha/machine-gmon.h, sysdeps/alpha/_mcount.S, sysdeps/alpha/ntohl.s, sysdeps/alpha/ntohs.s, sysdeps/alpha/strlen.S: New files. * sysdeps/alpha/divl.S, sysdeps/alpha/divlu.S, sysdeps/alpha/divq.S, sysdeps/alpha/divqu.S, sysdeps/alpha/divrem.m4, sysdeps/alpha/macros.m4, sysdeps/alpha/reml.S, sysdeps/alpha/remlu.S, sysdeps/alpha/remq.S, sysdeps/alpha/remqu.S, sysdeps/alpha/strlen.c: Removed. * sysdeps/generic/sbrk.c (__sbrk): argument is of type ptrdiff_t, not int. * sysdeps/alpha/__longjmp.c (__longjmp): moved dummy while loop to end of function to avoid a jump across NOPs. * sysdeps/alpha/Makefile (sysdep_routines): Removed all rules pertaining to integer division/remainder routines since new code doesn't require them. * sunrpc/xdr_mem.c, sunrpc/xdr_stdio.c: Use 4 instead of sizeof(long) where 32 bit quantities are consumed/stored. Various other minor 64-bit cleanups (casting). * sunrpc/xdr.c (xdr_int): test for sizeof(int)==4 to determine whether xdr_long or xdr_short should be used to encode an int. Notice that an xdr_long is 4 bytes independent of the architecture (otherwise no Alpha could interoperate with existing NFS servers, for example). Ditto for enums. * sunrpc/svc_udp.c (svcudp_recv): changed test from 4*sizeof(u_long) to 16 since it really wants 16 bytes. * sunrpc/svc.c (maskp): changed from u_long* to u_int32*. * sunrpc/rpc_cmsg.c (xdr_callmsg), sunrpc/svc_authux.c: increment "buf" pointer by casting it to a char* first since a long* may be 8 bytes or more and oa->oa_length may be any multiple of 4. * sunrpc/rpc/xdr.h (IXDR_GET_LONG, IXDR_PUT_LONG): change casts to u_int32_t (instead of u_long). * sunrpc/clnt_udp.c (clntudp_call): replaced sizeof(u_long) by 4 since it really is testing for 32 bits. Fixed casts to use u_int32 instead of u_long. * sunrpc/xdr_rec.c: Likewise. * sunrpc/clnt_tcp.c (clnttcp_call): replaced u_long by u_int32. * sunrpc/rpc/auth.h: Likewise. * limits.h (LONG_MAX, LONG_MIN, ULONG_MAX): use 64 bit values for Alpha. Tue Mar 19 13:27:49 1996 Roland McGrath <roland@charlie-brown.gnu.ai.mit.edu> * sysdeps/i386/fpu/__math.h: New file. Contributed by John C. Bowman <bowman@hagar.ph.utexas.edu>. Sun Mar 17 00:28:16 1996 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * sysdeps/posix/clock.c: Don't multiply the return value by CLOCKS_PER_SEC or CLK_TCK. * sysdeps/mach/hurd/getcwd.c: Fail with ENOENT if a parent directory scan finds no match. * posix/unistd.h (setpgrp): Declare no-arg version unless __FAVOR_BSD. * misc/bsd-compat.c (setpgrp): New function, two arg version. * sysdeps/stub/setpgid.c: Remove setpgrp alias. * sysdeps/mach/hurd/setpgid.c: Likewise. * sysdeps/unix/sysv/sysv4/setpgid.c: Likewise. * sysdeps/unix/common/syscalls.list (setpgid): Remove setpgrp alias. * sysdeps/unix/sysv/irix4/syscalls.list: Likewise. * sysdeps/unix/sysv/linux/setpgrp.c: Obsolete file removed. * posix/setpgrp.c (setpgrp): New file. * posix/Makefile (routines): Add setpgrp. Tue Feb 6 12:46:29 1996 David Mosberger-Tang <davidm@azstarnet.com> * libc-symbols.h (weak_alias, weak_symbol): added definitions for ECOFF (HAVE_ECOFF).
443 lines
12 KiB
C
443 lines
12 KiB
C
/* @(#)clnt_udp.c 2.2 88/08/01 4.0 RPCSRC */
|
|
/*
|
|
* 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(lint) && defined(SCCSIDS)
|
|
static char sccsid[] = "@(#)clnt_udp.c 1.39 87/08/11 Copyr 1984 Sun Micro";
|
|
#endif
|
|
|
|
/*
|
|
* clnt_udp.c, Implements a UDP/IP based, client side RPC.
|
|
*
|
|
* Copyright (C) 1984, Sun Microsystems, Inc.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <rpc/rpc.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/ioctl.h>
|
|
#include <netdb.h>
|
|
#include <errno.h>
|
|
#include <rpc/pmap_clnt.h>
|
|
|
|
extern int errno;
|
|
|
|
/*
|
|
* UDP bases client side rpc operations
|
|
*/
|
|
static enum clnt_stat clntudp_call();
|
|
static void clntudp_abort();
|
|
static void clntudp_geterr();
|
|
static bool_t clntudp_freeres();
|
|
static bool_t clntudp_control();
|
|
static void clntudp_destroy();
|
|
|
|
static struct clnt_ops udp_ops = {
|
|
clntudp_call,
|
|
clntudp_abort,
|
|
clntudp_geterr,
|
|
clntudp_freeres,
|
|
clntudp_destroy,
|
|
clntudp_control
|
|
};
|
|
|
|
/*
|
|
* Private data kept per client handle
|
|
*/
|
|
struct cu_data {
|
|
int cu_sock;
|
|
bool_t cu_closeit;
|
|
struct sockaddr_in cu_raddr;
|
|
int cu_rlen;
|
|
struct timeval cu_wait;
|
|
struct timeval cu_total;
|
|
struct rpc_err cu_error;
|
|
XDR cu_outxdrs;
|
|
u_int cu_xdrpos;
|
|
u_int cu_sendsz;
|
|
char *cu_outbuf;
|
|
u_int cu_recvsz;
|
|
char cu_inbuf[1];
|
|
};
|
|
|
|
/*
|
|
* Create a UDP based client handle.
|
|
* If *sockp<0, *sockp is set to a newly created UPD socket.
|
|
* If raddr->sin_port is 0 a binder on the remote machine
|
|
* is consulted for the correct port number.
|
|
* NB: It is the clients responsibility to close *sockp.
|
|
* NB: The rpch->cl_auth is initialized to null authentication.
|
|
* Caller may wish to set this something more useful.
|
|
*
|
|
* wait is the amount of time used between retransmitting a call if
|
|
* no response has been heard; retransmition occurs until the actual
|
|
* rpc call times out.
|
|
*
|
|
* sendsz and recvsz are the maximum allowable packet sizes that can be
|
|
* sent and received.
|
|
*/
|
|
CLIENT *
|
|
clntudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz)
|
|
struct sockaddr_in *raddr;
|
|
u_long program;
|
|
u_long version;
|
|
struct timeval wait;
|
|
register int *sockp;
|
|
u_int sendsz;
|
|
u_int recvsz;
|
|
{
|
|
CLIENT *cl;
|
|
register struct cu_data *cu;
|
|
struct timeval now;
|
|
struct rpc_msg call_msg;
|
|
|
|
cl = (CLIENT *)mem_alloc(sizeof(CLIENT));
|
|
if (cl == NULL) {
|
|
(void) fprintf(stderr, "clntudp_create: out of memory\n");
|
|
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
|
|
rpc_createerr.cf_error.re_errno = errno;
|
|
goto fooy;
|
|
}
|
|
sendsz = ((sendsz + 3) / 4) * 4;
|
|
recvsz = ((recvsz + 3) / 4) * 4;
|
|
cu = (struct cu_data *)mem_alloc(sizeof(*cu) + sendsz + recvsz);
|
|
if (cu == NULL) {
|
|
(void) fprintf(stderr, "clntudp_create: out of memory\n");
|
|
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
|
|
rpc_createerr.cf_error.re_errno = errno;
|
|
goto fooy;
|
|
}
|
|
cu->cu_outbuf = &cu->cu_inbuf[recvsz];
|
|
|
|
(void)gettimeofday(&now, (struct timezone *)0);
|
|
if (raddr->sin_port == 0) {
|
|
u_short port;
|
|
if ((port =
|
|
pmap_getport(raddr, program, version, IPPROTO_UDP)) == 0) {
|
|
goto fooy;
|
|
}
|
|
raddr->sin_port = htons(port);
|
|
}
|
|
cl->cl_ops = &udp_ops;
|
|
cl->cl_private = (caddr_t)cu;
|
|
cu->cu_raddr = *raddr;
|
|
cu->cu_rlen = sizeof (cu->cu_raddr);
|
|
cu->cu_wait = wait;
|
|
cu->cu_total.tv_sec = -1;
|
|
cu->cu_total.tv_usec = -1;
|
|
cu->cu_sendsz = sendsz;
|
|
cu->cu_recvsz = recvsz;
|
|
call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
|
|
call_msg.rm_direction = CALL;
|
|
call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
|
|
call_msg.rm_call.cb_prog = program;
|
|
call_msg.rm_call.cb_vers = version;
|
|
xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf,
|
|
sendsz, XDR_ENCODE);
|
|
if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) {
|
|
goto fooy;
|
|
}
|
|
cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs));
|
|
if (*sockp < 0) {
|
|
int dontblock = 1;
|
|
|
|
*sockp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
|
if (*sockp < 0) {
|
|
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
|
|
rpc_createerr.cf_error.re_errno = errno;
|
|
goto fooy;
|
|
}
|
|
/* attempt to bind to prov port */
|
|
(void)bindresvport(*sockp, (struct sockaddr_in *)0);
|
|
/* the sockets rpc controls are non-blocking */
|
|
(void)ioctl(*sockp, FIONBIO, (char *) &dontblock);
|
|
cu->cu_closeit = TRUE;
|
|
} else {
|
|
cu->cu_closeit = FALSE;
|
|
}
|
|
cu->cu_sock = *sockp;
|
|
cl->cl_auth = authnone_create();
|
|
return (cl);
|
|
fooy:
|
|
if (cu)
|
|
mem_free((caddr_t)cu, sizeof(*cu) + sendsz + recvsz);
|
|
if (cl)
|
|
mem_free((caddr_t)cl, sizeof(CLIENT));
|
|
return ((CLIENT *)NULL);
|
|
}
|
|
|
|
CLIENT *
|
|
clntudp_create(raddr, program, version, wait, sockp)
|
|
struct sockaddr_in *raddr;
|
|
u_long program;
|
|
u_long version;
|
|
struct timeval wait;
|
|
register int *sockp;
|
|
{
|
|
|
|
return(clntudp_bufcreate(raddr, program, version, wait, sockp,
|
|
UDPMSGSIZE, UDPMSGSIZE));
|
|
}
|
|
|
|
static enum clnt_stat
|
|
clntudp_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout)
|
|
register CLIENT *cl; /* client handle */
|
|
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 */
|
|
struct timeval utimeout; /* seconds to wait before giving up */
|
|
{
|
|
register struct cu_data *cu = (struct cu_data *)cl->cl_private;
|
|
register XDR *xdrs;
|
|
register int outlen;
|
|
register int inlen;
|
|
int fromlen;
|
|
#ifdef FD_SETSIZE
|
|
fd_set readfds;
|
|
fd_set mask;
|
|
#else
|
|
int readfds;
|
|
register int mask;
|
|
#endif /* def FD_SETSIZE */
|
|
struct sockaddr_in from;
|
|
struct rpc_msg reply_msg;
|
|
XDR reply_xdrs;
|
|
struct timeval time_waited;
|
|
bool_t ok;
|
|
int nrefreshes = 2; /* number of times to refresh cred */
|
|
struct timeval timeout;
|
|
|
|
if (cu->cu_total.tv_usec == -1) {
|
|
timeout = utimeout; /* use supplied timeout */
|
|
} else {
|
|
timeout = cu->cu_total; /* use default timeout */
|
|
}
|
|
|
|
time_waited.tv_sec = 0;
|
|
time_waited.tv_usec = 0;
|
|
call_again:
|
|
xdrs = &(cu->cu_outxdrs);
|
|
xdrs->x_op = XDR_ENCODE;
|
|
XDR_SETPOS(xdrs, cu->cu_xdrpos);
|
|
/*
|
|
* the transaction is the first thing in the out buffer
|
|
*/
|
|
(*(u_short *)(cu->cu_outbuf))++;
|
|
if ((! XDR_PUTLONG(xdrs, (long *)&proc)) ||
|
|
(! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
|
|
(! (*xargs)(xdrs, argsp)))
|
|
return (cu->cu_error.re_status = RPC_CANTENCODEARGS);
|
|
outlen = (int)XDR_GETPOS(xdrs);
|
|
|
|
send_again:
|
|
if (sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0,
|
|
(struct sockaddr *)&(cu->cu_raddr), cu->cu_rlen)
|
|
!= outlen) {
|
|
cu->cu_error.re_errno = errno;
|
|
return (cu->cu_error.re_status = RPC_CANTSEND);
|
|
}
|
|
|
|
/*
|
|
* Hack to provide rpc-based message passing
|
|
*/
|
|
if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
|
|
return (cu->cu_error.re_status = RPC_TIMEDOUT);
|
|
}
|
|
/*
|
|
* sub-optimal code appears here because we have
|
|
* some clock time to spare while the packets are in flight.
|
|
* (We assume that this is actually only executed once.)
|
|
*/
|
|
reply_msg.acpted_rply.ar_verf = _null_auth;
|
|
reply_msg.acpted_rply.ar_results.where = resultsp;
|
|
reply_msg.acpted_rply.ar_results.proc = xresults;
|
|
#ifdef FD_SETSIZE
|
|
FD_ZERO(&mask);
|
|
FD_SET(cu->cu_sock, &mask);
|
|
#else
|
|
mask = 1 << cu->cu_sock;
|
|
#endif /* def FD_SETSIZE */
|
|
for (;;) {
|
|
readfds = mask;
|
|
switch (select(_rpc_dtablesize(), &readfds, (int *)NULL,
|
|
(int *)NULL, &(cu->cu_wait))) {
|
|
|
|
case 0:
|
|
time_waited.tv_sec += cu->cu_wait.tv_sec;
|
|
time_waited.tv_usec += cu->cu_wait.tv_usec;
|
|
while (time_waited.tv_usec >= 1000000) {
|
|
time_waited.tv_sec++;
|
|
time_waited.tv_usec -= 1000000;
|
|
}
|
|
if ((time_waited.tv_sec < timeout.tv_sec) ||
|
|
((time_waited.tv_sec == timeout.tv_sec) &&
|
|
(time_waited.tv_usec < timeout.tv_usec)))
|
|
goto send_again;
|
|
return (cu->cu_error.re_status = RPC_TIMEDOUT);
|
|
|
|
/*
|
|
* buggy in other cases because time_waited is not being
|
|
* updated.
|
|
*/
|
|
case -1:
|
|
if (errno == EINTR)
|
|
continue;
|
|
cu->cu_error.re_errno = errno;
|
|
return (cu->cu_error.re_status = RPC_CANTRECV);
|
|
}
|
|
do {
|
|
fromlen = sizeof(struct sockaddr);
|
|
inlen = recvfrom(cu->cu_sock, cu->cu_inbuf,
|
|
(int) cu->cu_recvsz, 0,
|
|
(struct sockaddr *)&from, &fromlen);
|
|
} while (inlen < 0 && errno == EINTR);
|
|
if (inlen < 0) {
|
|
if (errno == EWOULDBLOCK)
|
|
continue;
|
|
cu->cu_error.re_errno = errno;
|
|
return (cu->cu_error.re_status = RPC_CANTRECV);
|
|
}
|
|
if (inlen < 4)
|
|
continue;
|
|
/* see if reply transaction id matches sent id */
|
|
if (*((u_int32_t *)(cu->cu_inbuf)) != *((u_int32_t *)(cu->cu_outbuf)))
|
|
continue;
|
|
/* we now assume we have the proper reply */
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* now decode and validate the response
|
|
*/
|
|
xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)inlen, XDR_DECODE);
|
|
ok = xdr_replymsg(&reply_xdrs, &reply_msg);
|
|
/* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */
|
|
if (ok) {
|
|
_seterr_reply(&reply_msg, &(cu->cu_error));
|
|
if (cu->cu_error.re_status == RPC_SUCCESS) {
|
|
if (! AUTH_VALIDATE(cl->cl_auth,
|
|
&reply_msg.acpted_rply.ar_verf)) {
|
|
cu->cu_error.re_status = RPC_AUTHERROR;
|
|
cu->cu_error.re_why = AUTH_INVALIDRESP;
|
|
}
|
|
if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
|
|
xdrs->x_op = XDR_FREE;
|
|
(void)xdr_opaque_auth(xdrs,
|
|
&(reply_msg.acpted_rply.ar_verf));
|
|
}
|
|
} /* end successful completion */
|
|
else {
|
|
/* maybe our credentials need to be refreshed ... */
|
|
if (nrefreshes > 0 && AUTH_REFRESH(cl->cl_auth)) {
|
|
nrefreshes--;
|
|
goto call_again;
|
|
}
|
|
} /* end of unsuccessful completion */
|
|
} /* end of valid reply message */
|
|
else {
|
|
cu->cu_error.re_status = RPC_CANTDECODERES;
|
|
}
|
|
return (cu->cu_error.re_status);
|
|
}
|
|
|
|
static void
|
|
clntudp_geterr(cl, errp)
|
|
CLIENT *cl;
|
|
struct rpc_err *errp;
|
|
{
|
|
register struct cu_data *cu = (struct cu_data *)cl->cl_private;
|
|
|
|
*errp = cu->cu_error;
|
|
}
|
|
|
|
|
|
static bool_t
|
|
clntudp_freeres(cl, xdr_res, res_ptr)
|
|
CLIENT *cl;
|
|
xdrproc_t xdr_res;
|
|
caddr_t res_ptr;
|
|
{
|
|
register struct cu_data *cu = (struct cu_data *)cl->cl_private;
|
|
register XDR *xdrs = &(cu->cu_outxdrs);
|
|
|
|
xdrs->x_op = XDR_FREE;
|
|
return ((*xdr_res)(xdrs, res_ptr));
|
|
}
|
|
|
|
static void
|
|
clntudp_abort(/*h*/)
|
|
/*CLIENT *h;*/
|
|
{
|
|
}
|
|
|
|
static bool_t
|
|
clntudp_control(cl, request, info)
|
|
CLIENT *cl;
|
|
int request;
|
|
char *info;
|
|
{
|
|
register struct cu_data *cu = (struct cu_data *)cl->cl_private;
|
|
|
|
switch (request) {
|
|
case CLSET_TIMEOUT:
|
|
cu->cu_total = *(struct timeval *)info;
|
|
break;
|
|
case CLGET_TIMEOUT:
|
|
*(struct timeval *)info = cu->cu_total;
|
|
break;
|
|
case CLSET_RETRY_TIMEOUT:
|
|
cu->cu_wait = *(struct timeval *)info;
|
|
break;
|
|
case CLGET_RETRY_TIMEOUT:
|
|
*(struct timeval *)info = cu->cu_wait;
|
|
break;
|
|
case CLGET_SERVER_ADDR:
|
|
*(struct sockaddr_in *)info = cu->cu_raddr;
|
|
break;
|
|
default:
|
|
return (FALSE);
|
|
}
|
|
return (TRUE);
|
|
}
|
|
|
|
static void
|
|
clntudp_destroy(cl)
|
|
CLIENT *cl;
|
|
{
|
|
register struct cu_data *cu = (struct cu_data *)cl->cl_private;
|
|
|
|
if (cu->cu_closeit) {
|
|
(void)close(cu->cu_sock);
|
|
}
|
|
XDR_DESTROY(&(cu->cu_outxdrs));
|
|
mem_free((caddr_t)cu, (sizeof(*cu) + cu->cu_sendsz + cu->cu_recvsz));
|
|
mem_free((caddr_t)cl, sizeof(CLIENT));
|
|
}
|