glibc/sunrpc/clnt_udp.c
Ulrich Drepper 7cc27f440c update from main archive 970209
1997-02-09 02:59  Ulrich Drepper  <drepper@cygnus.com>

	* version.h (VERSION): Bump to 2.0.2.

	* posix/Makefile (routines): Add getopt_init.
	* posix/getopt.c: Don't get environment variable with nonoption
	flags here.  Depend on __getopt_nonoption_flags variable filled
	somewhere else.  This is necessary since the variable must be
	removed even when getopt isn't used in case exec(2) gets called.
	* posix/getopt_init.c: New file.  Initialize __getopt_nonoption_flags
	and remove environment variable.
	* sysdeps/i386/init-first.c: Call __getopt_clean_environment.
	* sysdeps/mach/hurd/i386/init-first.c: Likewise.
	* sysdeps/stub/init-first.c: Likewise.
	* sysdeps/unix/sysv/linux/init-first.c: Likewise.

	* sysdeps/generic/dl-sysdep.c (_dl_sysdep_start): Recognize
	AT_PAGESZ entry in auxiliary vector and store value in _dl_pagesize.

	* sysdeps/generic/crypt-entry.h: Return EOPNOTSUPP when DES
	encryption is wanted.

	* libio/vsnprintf.c: If MAXLEN is 0 return 0.
	* stdio/vsnprintf.c: Likewise.
	Reported by Philip Blundell <pjb27@cam.ac.uk>.

1997-02-07 17:43  Ulrich Drepper  <drepper@cygnus.com>

	* sysdeps/generic/sysd-stdio.c: Include <errno.h>.
	Change PTR to void *.
	* sysdeps/posix/vdprintf.c: Change PTR to void *.
	Reported by Brian Oxley <boxley%dev.cm.ssb.com@clipper.ssb.com>.

1997-02-07 17:41  Philip Blundell <pjb27@cam.ac.uk>

	* sysdeps/unix/sysv/linux/socketbits.h: Fix typo.

1997-02-06 13:49  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* rellns-sh: No need to check for existance of first parameter.

1997-02-06 14:50  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* sysdeps/posix/getcwd.c (__getcwd): Fix resource leaks.  Reported
	by David Holland <dholland@eecs.harvard.edu>.

1997-02-06 14:38  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* sunrpc/clnt_tcp.c (readtcp): Pass copy of timeout value to
	select, in case it is modified by the latter.
	* sunrpc/clnt_udp.c (clntudp_call): Likewise.
	* sunrpc/pmap_rmt.c (clnt_broadcast): Likewise.
	* sunrpc/svc_tcp.c (readtcp): Likewise.

	* sunrpc/svc_authux.c (_svcauth_unix): Fix type of area_gids
	array.

	* sunrpc/authuxprot.c (xdr_authunix_parms): Check size of uid_t
	and gid_t.

	* sunrpc/auth_unix.c (authunix_validate): Fix type of second
	argument.

1997-02-06 14:29  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* elf/Makefile (extra-objs): Don't zap previous value.
	* Makefile (before-compile): Likewise.  Don't add gnu/lib-names.h
	twice.

1997-02-06 14:19  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* sysdeps/unix/sysv/linux/m68k/brk.c: Add workaround for
	braindamage (sigh!).

1997-02-06 17:10  Jim Meyering  <meyering@asic.sc.ti.com>

	* manual/memory.texi: Correct `copystring' example for obstacks.

1997-02-06 14:10  Ulrich Drepper  <drepper@cygnus.com>

	* Makeconfig: Don't use [:lower:] and [:upper:] in tr since old
	GNU tr don't grok it.

1997-02-03 21:13  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* sysdeps/unix/sysv/linux/socketbits.h [__GNUC__<2] (struct cmsghdr):
	Don't use GNU C extensions.
	(CMSG_DATA): Use portable definition.

1997-02-05 05:58  Ulrich Drepper  <drepper@cygnus.com>

	* elf/ldd.bash.in: Add test for read permission and print appropriate
	message.  Change warning and error messages to print "ldd: " at start.
	* elf/ldd.sh.in: Likewise.

	* stdlib/Makefile (routines): Add atoll.
	* stdlib/atoll.c: New file.
	* stdlib/stdlib.h: Add prototype and optimization for atoll.

	* stdlib/a64l.c: Update copyright.
	* stdlib/abs.c: Likewise.
	* stdlib/atof.c: Likewise.
	* stdlib/atoi.c: Likewise.
	* stdlib/atol.c: Likewise.
	* stdlib/bsearch.c: Likewise.
	* stdlib/exit.c: Likewise.
	* stdlib/fpioconst.c: Likewise.
	* stdlib/fpioconst.h: Likewise.
	* stdlib/jrand48.c: Likewise.
	* stdlib/jrand48_r.c: Likewise.
	* stdlib/labs.c: Likewise.
	* stdlib/lcong48.c: Likewise.
	* stdlib/lcong48_r.c: Likewise.
	* stdlib/llabs.c: Likewise.
	* stdlib/lrand48.c: Likewise.
	* stdlib/lrand48_r.c: Likewise.
	* stdlib/mblen.c: Likewise.
	* stdlib/mbstowcs.c: Likewise.
	* stdlib/mbtowc.c: Likewise.
	* stdlib/mp_clz_tab.c: Likewise.
	* stdlib/mrand48.c: Likewise.
	* stdlib/mrand48_r.c: Likewise.
	* stdlib/msort.c: Likewise.
	* stdlib/nrand48.c: Likewise.
	* stdlib/nrand48_r.c: Likewise.
	* stdlib/qsort.c: Likewise.
	* stdlib/rpmatch.c: Likewise.
	* stdlib/seed48.c: Likewise.
	* stdlib/seed48_r.c: Likewise.
	* stdlib/srand48.c: Likewise.
	* stdlib/srand48_r.c: Likewise.
	* stdlib/strtod.c: Likewise.
	* stdlib/wcstombs.c: Likewise.
	* stdlib/wctomb.c: Likewise.

1997-02-05 05:08  Ulrich Drepper  <drepper@cygnus.com>

	* stdlib/mp_clz_tab.c (__clz_tab): Follow change in GMP and define
	as const.

1997-02-04 23:57  Fila Kolodny  <fila@ibi.com>

	* sysdeps/unix/sysv/linux/socketbits.h: Define __need_NULL before
	including <stddef.h>.

1997-02-03 20:01  H.J. Lu  <hjl@gnu.ai.mit.edu>

	* time/Makefile (tzbases, tzlinks): New.
	(tzfiles): Changed to $(tzbases) $(tzlinks).
	($(tzfiles:%=$(objpfx)z.%): Make $(tzlinks) depend on $(tzbases).

1997-02-02 12:13  H.J. Lu  <hjl@gnu.ai.mit.edu>

	* Makefile (install): Ignore error from ldconfig.

	* time/zic.c (mkdirs): Double check the error return of mkdir ().

1997-02-04 22:01  Ulrich Drepper  <drepper@cygnus.com>

	* stdio-common/vfprintf.c: Prepare to use __va_copy for architectures
	like PPC where va_list is no integral type.

1997-02-04 15:27  Roma Ekzhanov  <ekzhanov@paragraph.com>

	* posix/getopt.c (exchange): Don't allocate nonoption_flags array
	if nonoption_flags_len == -1.
1997-02-10 03:19:57 +00:00

446 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>
#ifndef errno
extern int errno;
#endif
/*
* 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; retransmission 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 (;;) {
struct timeval timeout = cu->cu_wait;
readfds = mask;
switch (select(_rpc_dtablesize(), &readfds, (int *)NULL,
(int *)NULL, &timeout)) {
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));
}