/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Portions of this source code were derived from Berkeley
* 4.3 BSD under license from the Regents of the University of
* California.
*/
/*
* Implements a connectionless client side RPC.
*/
#include "mt.h"
#include "rpc_mt.h"
#include <assert.h>
#include <errno.h>
#include <syslog.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
extern int __rpc_timeval_to_msec(struct timeval *);
caddr_t);
static struct clnt_ops *clnt_dg_ops(void);
/*
* This machinery implements per-fd locks for MT-safety. It is not
* sufficient to do per-CLIENT handle locks for MT-safety because a
* user may create more than one CLIENT handle with the same fd behind
* it.
*
* The current implementation holds locks across the entire RPC and reply,
* including retransmissions. Yes, this is silly, and as soon as this
* code is proven to work, this should be the first thing fixed. One step
* at a time.
*/
/*
* FD Lock handle used by various MT sync. routines
*/
/*
* Private data kept per client handle
*/
struct cu_data {
char *cu_outbuf_start;
};
/*
* Connection less client creation returns with client handle parameters.
* Default options are set, which the user can change using clnt_control().
* fd should be open and bound.
* NB: The rpch->cl_auth is initialized to null authentication.
* Caller may wish to set this something more useful.
*
* sendsz and recvsz are the maximum allowable packet sizes that can be
* sent and received. Normally they are the same, but they can be
* changed to improve the program efficiency and buffer allocation.
* If they are 0, use the transport default.
*
* If svcaddr is NULL, returns NULL.
*/
CLIENT *
{
goto err1;
}
return (NULL);
}
return (NULL);
}
/*
* Setup to rcv datagram error, we ignore any errors returned from
* __rpc_tli_set_options() as SO_DGRAM_ERRIND is only relevant to
* we are using a connection less transport.
*/
1);
/*
* Find the receive and the send size
*/
return (NULL);
}
goto err1;
/*
* Should be multiple of 4 for XDR.
*/
goto err1;
goto err1;
/* Other values can also be set through clnt_control() */
goto err2;
}
goto err1;
}
/*
* By default, closeit is always FALSE. It is users responsibility
* to do a t_close on it, else the user may use clnt_control
*/
return (cl);
err1:
err2:
if (cl) {
if (cu) {
}
}
return (NULL);
}
static enum clnt_stat
{
/* LINTED pointer alignment */
int outlen;
return (RPC_FAILED);
}
} else {
}
time_waited.tv_sec = 0;
time_waited.tv_usec = 0;
XDR_SETPOS(xdrs, 0);
/*
* Due to little endian byte order, it is necessary to convert to host
* format before incrementing xid.
*/
/* LINTED pointer cast */
/* LINTED pointer cast */
}
} else {
/* LINTED pointer alignment */
IXDR_PUT_U_INT32(u, proc);
}
}
}
/*
* Hack to provide rpc-based message passing
*/
}
/*
* 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.)
*/
/*
* Set polling time so that we don't wait for
* longer than specified by the total time to wait,
* or the retransmit time.
*/
}
/*
* this could happen if time_waited >= timeout
*/
}
for (;;) {
case -1:
rpc_callerr.re_terrno = 0;
}
/*FALLTHROUGH*/
case 0:
/*
* update time waited
*/
}
while (time_waited.tv_usec < 0) {
}
/*
* decrement time left to poll by same amount
*/
}
}
/*
* if there's time left to poll, poll again
*/
continue;
/*
* if there's more time left, retransmit;
* otherwise, return timeout error
*/
/*
* update retransmit_time
*/
}
retransmit_time.tv_usec = 0;
}
/*
* redo AUTH_MARSHAL if AUTH_DES or RPCSEC_GSS.
*/
AUTH_DES ||
goto call_again;
else
goto send_again;
}
default:
break;
}
/*
* Note: we're faking errno here because we
* previously would have expected select() to
* return -1 with errno EBADF. Poll(BA_OS)
* returns 0 and sets the POLLNVAL revents flag
* instead.
*/
return (-1);
}
/* We have some data now */
do {
moreflag = 0;
/*
* Drop this packet. I aint got any
* more space.
*/
res = -1;
/* I should not really be doing this */
errno = 0;
/*
* XXX: Not really Buffer overflow in the
* sense of TLI.
*/
}
if (res < 0) {
#ifdef sun
#else
#endif
continue;
continue;
else if (err == 1)
} else {
}
}
continue;
/* see if reply transaction id matches sent id */
/* LINTED pointer alignment */
/* LINTED pointer alignment */
goto timeout;
/* we now assume we have the proper reply */
break;
}
/*
* now decode and validate the response
*/
/* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */
if (ok) {
else
RPCSEC_GSS) {
if (rpc_callerr.re_status ==
}
}
} /* end successful completion */
/*
* If unsuccesful AND error is an authentication error
* then refresh credentials and try again, else break
*/
/* maybe our credentials need to be refreshed ... */
if (nrefreshes-- &&
goto call_again;
else
/*
* We are setting rpc_callerr here given that
* libnsl is not reentrant thereby
* reinitializing the TSD. If not set here then
* success could be returned even though refresh
* failed.
*/
/* end of unsuccessful completion */
/* free verifier */
(void) xdr_opaque_auth(xdrs,
}
} /* end of valid reply message */
else {
}
return (rpc_callerr.re_status);
}
static enum clnt_stat
{
/* LINTED pointer alignment */
int outlen;
return (RPC_FAILED);
}
XDR_SETPOS(xdrs, 0);
/*
* Due to little endian byte order, it is necessary to convert to host
* format before incrementing xid.
*/
/* LINTED pointer alignment */
/* LINTED pointer cast */
}
} else {
/* LINTED pointer alignment */
IXDR_PUT_U_INT32(u, proc);
}
}
}
}
static void
{
/* LINTED pointer alignment */
*errp = rpc_callerr;
}
static bool_t
{
/* LINTED pointer alignment */
return (stat);
}
/* ARGSUSED */
static void
{
}
static bool_t
{
/* LINTED pointer alignment */
return (RPC_FAILED);
}
switch (request) {
case CLSET_FD_CLOSE:
return (TRUE);
case CLSET_FD_NCLOSE:
return (TRUE);
}
/* for other requests which use info */
return (FALSE);
}
switch (request) {
case CLSET_TIMEOUT:
/* LINTED pointer alignment */
return (FALSE);
}
/* LINTED pointer alignment */
break;
case CLGET_TIMEOUT:
/* LINTED pointer alignment */
break;
case CLGET_SERVER_ADDR: /* Give him the fd address */
/* Now obsolete. Only for backword compatibility */
break;
case CLSET_RETRY_TIMEOUT:
/* LINTED pointer alignment */
return (FALSE);
}
/* LINTED pointer alignment */
break;
case CLGET_RETRY_TIMEOUT:
/* LINTED pointer alignment */
break;
case CLGET_FD:
/* LINTED pointer alignment */
break;
case CLGET_SVC_ADDR:
/* LINTED pointer alignment */
break;
case CLSET_SVC_ADDR: /* set to new address */
/* LINTED pointer alignment */
return (FALSE);
}
}
break;
case CLGET_XID:
/*
* use the knowledge that xid is the
* first element in the call structure *.
* This will get the xid of the PREVIOUS call
*/
/* LINTED pointer alignment */
break;
case CLSET_XID:
/* This will set the xid of the NEXT call */
/* LINTED pointer alignment */
/* decrement by 1 as clnt_dg_call() increments once */
break;
case CLGET_VERS:
/*
* This RELIES on the information that, in the call body,
* the version number field is the fifth field from the
* begining of the RPC header. MUST be changed if the
* call_struct is changed
*/
/* LINTED pointer alignment */
4 * BYTES_PER_XDR_UNIT));
break;
case CLSET_VERS:
/* LINTED pointer alignment */
/* LINTED pointer alignment */
break;
case CLGET_PROG:
/*
* This RELIES on the information that, in the call body,
* the program number field is the fourth field from the
* begining of the RPC header. MUST be changed if the
* call_struct is changed
*/
/* LINTED pointer alignment */
3 * BYTES_PER_XDR_UNIT));
break;
case CLSET_PROG:
/* LINTED pointer alignment */
/* LINTED pointer alignment */
break;
default:
return (FALSE);
}
return (TRUE);
}
static void
{
/* LINTED pointer alignment */
if (cu->cu_closeit)
}
static struct clnt_ops *
clnt_dg_ops(void)
{
/* VARIABLES PROTECTED BY ops_lock: ops */
}
return (&ops);
}
/*
* Make sure that the time is not garbage. -1 value is allowed.
*/
static bool_t
{
}
/*
* Receive a unit data error indication.
* Below even when t_alloc() fails we pass uderr=NULL to t_rcvuderr()
* so as to just clear the error indication.
*/
static int
{
int old;
return (0);
return (0);
}
return (1);
}
if (uderr)
return (-1);
}