Files
cdesktop/cde/lib/tt/lib/mp/mp_rpc_client.C
2018-09-30 17:27:04 -06:00

359 lines
9.1 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these libraries and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
//%% (c) Copyright 1993, 1994 Hewlett-Packard Company
//%% (c) Copyright 1993, 1994 International Business Machines Corp.
//%% (c) Copyright 1993, 1994 Sun Microsystems, Inc.
//%% (c) Copyright 1993, 1994 Novell, Inc.
//%% $TOG: mp_rpc_client.C /main/9 1999/09/08 18:21:02 mgreess $
/*
*
* mp_rpc_client.cc
*
* Copyright (c) 1990 by Sun Microsystems, Inc.
*/
#include <sys/time.h>
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <fcntl.h>
#include <unistd.h>
#include "tt_options.h"
#include "mp/mp_auth.h"
#include "mp/mp_rpc_client.h"
#include "mp/mp_xdr_functions.h"
#include "util/tt_host.h"
#include "util/tt_port.h"
#if defined(_AIX)
/* AIX's FD_ZERO macro uses bzero() without declaring it. */
#include <strings.h>
/* And arpa/inet.h has a buggy declaration of inet_addr */
extern "C" in_addr_t inet_addr(const char *);
#endif
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <memory.h>
#if defined(sgi)
/* SGI's FD_ZERO macro uses bzero() without declaring it. */
#include <CC/libc.h>
#endif
#include <sys/resource.h>
#include <util/tt_global_env.h>
#include <mp/mp_rpc_fns.h>
/*
* Constructs an rpc client.
*/
_Tt_rpc_client::
_Tt_rpc_client(int conn_socket)
{
_socket = conn_socket;
_client = (CLIENT *)0;
_program = 0;
_version = 0;
_server_uid = 0;
_clnt_stat = RPC_SUCCESS;
#if defined(OPT_TLI)
_server_addr = 0;
#else
_server_addr.sin_family = 0;
_server_addr.sin_port = 0;
#endif
}
/*
* Destroys an rpc client (breaks off connections)
*/
_Tt_rpc_client::
~_Tt_rpc_client()
{
if (_client != (CLIENT *)0) {
clnt_destroy(_client);
}
_host = (_Tt_host *)0;
}
/*
* Returns the socket associated with an rpc client. --> it would be
* nice to use this socket rather than open up a new one when signalling
* procids.
*/
int _Tt_rpc_client::
socket()
{
return(_socket);
}
/*
* create client connection to host,program,version
*/
int _Tt_rpc_client::
init(_Tt_host_ptr &host, int program, int version,
uid_t servuid, _Tt_auth &auth)
{
int optval;
optval = (_socket == RPC_ANYSOCK);
_auth = auth;
_host = host;
_program = program;
_version = version;
_server_uid = servuid;
if (_client != (CLIENT *)0) {
if (_auth.auth_level() == _TT_AUTH_UNIX) {
auth_destroy(_client->cl_auth);
}
clnt_destroy(_client);
}
#if defined(OPT_SECURE_RPC)
if (_auth.auth_level() == _TT_AUTH_DES) {
if (_server_uid == 0) {
host2netname(_servername, (char *)_host->name(), 0);
} else {
user2netname(_servername, _server_uid, 0);
}
}
#endif /* OPT_SECURE_RPC */
#ifndef OPT_TLI
memset(&_server_addr, 0, sizeof(_server_addr));
_server_addr.sin_family = AF_INET;
_server_addr.sin_port = htons((optval) ? 0 : 4000);
_server_addr.sin_addr.s_addr = inet_addr((char *)(_host->stringaddr()));
_client = clnttcp_create(&_server_addr, _program,
_version, &_socket, 4000, 4000);
if (_client == 0) {
// XXX only when in some kind of debug mode
//clnt_pcreateerror("_Tt_rpc_client::init(): clnttcp_create()");
return 0;
}
if (_auth.auth_level() == _TT_AUTH_UNIX) {
_client->cl_auth = authunix_create_default();
}
if (optval) {
#ifndef linux
if (setsockopt(_socket, SOL_SOCKET, SO_USELOOPBACK,
(char *)&optval, sizeof(int)) == -1) {
_tt_syslog( 0, LOG_ERR, "_Tt_rpc_client::init(): "
"setsockopt(SO_USELOOPBACK): %m");
}
#endif
if (setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY,
(char *)&optval, sizeof(int)) == -1) {
_tt_syslog( 0, LOG_ERR, "_Tt_rpc_client::init(): "
"setsockopt(TCP_NODELAY): %m");
}
}
#else
_client = clnt_create((char *)_host->name(),
_program, _version, "circuit_v");
if (_client == 0) {
// XXX only when in some kind of debug mode
//clnt_pcreateerror( "_Tt_rpc_client::init(): clnt_create()" );
return 0;
}
if (!clnt_control(_client, CLGET_FD, (char *)&_socket)) {
// I cannot imagine how this could ever fail at this point.
return 0;
}
// We used to call _tt_tli_set_nodelay here on the RPC connection.
// This stopped working mysteriously, suddenly the endpoint started
// coming back in state T_DATAXFER instead of T_IDLE from clnt_create.
// Fortunately, in the meantime the TIRPC library has started
// setting NODELAY on RPC/TCP connections, so we don't need to
// do it here anymore anyway.
if (_auth.auth_level() == _TT_AUTH_UNIX) {
_client->cl_auth = authunix_create_default();
}
#endif // !OPT_TLI
// Set close-on-exec bit so a libtt client which forks and execs won't
// be short some fd's in the child.
#if defined(__linux__)
// JET - for linux, we need to do this properly - I don't know
// how the original code below can be correct, so we'll do it
// differently.
{
long flags;
if ((flags = fcntl(_socket, F_GETFD)) == -1)
{
_tt_syslog( 0, LOG_ERR, "_Tt_rpc_client::init(): "
"fcntl(F_GETFD): %m");
}
else
{
if (fcntl(_socket, F_SETFD, flags | FD_CLOEXEC) == -1)
_tt_syslog( 0, LOG_ERR, "_Tt_rpc_client::init(): "
"fcntl(F_SETFD): %m");
}
}
#else
if (-1==fcntl(_socket, F_SETFD, 1)) {
_tt_syslog( 0, LOG_ERR, "_Tt_rpc_client::init(): "
"fcntl(F_SETFD): %m");
}
#endif // linux
return(1);
}
/*
* invoke rpc procedure
*/
clnt_stat _Tt_rpc_client::
call(int procnum, xdrproc_t inproc, char *in,
xdrproc_t outproc, char *out, int timeout)
{
fd_set bogus;
timeval tmout;
timeval total_timeout;
struct sigaction curr_action;
int need2reset_sigpipe = 0;
_Tt_auth_iceauth_args args;
if (_client == (CLIENT *)0) {
return(RPC_CANTSEND);
}
total_timeout.tv_sec = ((timeout < 0) ? 0 : timeout);
total_timeout.tv_usec = 0;
clnt_control(_client, CLSET_TIMEOUT, (char *) &total_timeout);
switch (_auth.auth_level()) {
case _TT_AUTH_UNIX:
break;
case _TT_AUTH_ICEAUTH:
break;
#if defined(OPT_SECURE_RPC)
case _TT_AUTH_DES:
#ifdef OPT_TLI
_client->cl_auth =
authdes_seccreate(_servername, 60, (char *)_host->name(),
(des_block *)0);
if (_client->cl_auth == 0) {
_tt_syslog( 0, LOG_WARNING, "authdes_seccreate(): 0" );
// XXX what todo when authdes_seccreate() fails?
return RPC_AUTHERROR;
}
#else
_client->cl_auth =
authdes_create(_servername, 60, &_server_addr,
(des_block *)0);
if (_client->cl_auth == 0) {
_tt_syslog( 0, LOG_WARNING, "authdes_seccreate(): 0" );
// XXX what todo when authdes_seccreate() fails?
return RPC_AUTHERROR;
}
#endif /* OPT_TLI */
break;
#endif /* OPT_SECURE_RPC */
case _TT_AUTH_NONE:
break;
default:
return(RPC_AUTHERROR);
}
if (timeout == 0) {
FD_ZERO(&bogus);
FD_SET(_socket, &bogus);
tmout.tv_sec = 0;
tmout.tv_usec = 0;
select(FD_SETSIZE, &bogus, 0, 0, &tmout);
if (FD_ISSET(_socket, &bogus)) {
return(RPC_CANTSEND);
}
}
//
// tcp write errors (when the rpc_server on the other end dies)
// cause a SIGPIPE. We need to make sure the SIGPIPE is caught,
// or the process dies.
//
if (sigaction(SIGPIPE, 0, &curr_action) != 0) {
_tt_syslog( 0, LOG_ERR, "sigaction(): %m" );
}
#if defined(OPT_BUG_SUNOS_5)
if ((SIG_TYP)curr_action.sa_handler == SIG_DFL)
#else
if (curr_action.sa_handler == SIG_DFL)
#endif
{
need2reset_sigpipe = 1;
signal(SIGPIPE, SIG_IGN);
}
if (_TT_AUTH_ICEAUTH == _auth.auth_level()) {
args.auth_level = _auth.auth_level();
args.auth_cookie = _auth.auth_cookie();
args.inproc = (xdr_auth_proc_t) inproc;
args.inargs = (caddr_t) in;
_clnt_stat = clnt_call(_client, procnum,
(xdrproc_t) tt_xdr_auth_iceauth_args,
(char*) &args,
outproc, out,
total_timeout);
}
else {
_clnt_stat = clnt_call(_client, procnum,
inproc, in,
outproc, out,
total_timeout);
}
if (need2reset_sigpipe) {
signal(SIGPIPE, SIG_DFL);
}
#if !defined(OPT_BUG_RPCINTR)
if (_clnt_stat == RPC_INTR) {
return(RPC_CANTSEND);
}
#endif
if (_auth.auth_level() == _TT_AUTH_DES) {
auth_destroy(_client->cl_auth);
}
return(_clnt_stat);
}