Files
cdesktop/cde/lib/tt/lib/mp/mp_session.C
Frederic Koehler 66e428596b mp_session: Always use global displayname
This code tried to automatically generate the X DISPLAY
from the combination of the hostname and display number;
however 127.0.0.1:0 is normally rejected by X11, so this
technique is no good. Fixes dticon hang on startup, caused by
XOpenDisplay failure leading to this message from tttrace:
tt_default_session_set(0x0x875190=="X 127.0.0.1 0") = 1032 (TT_ERR_ACCESS)
2012-08-14 20:37:59 -06:00

949 lines
25 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 librararies 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_session.C /main/13 1999/09/16 13:46:46 mgreess $
/*
* @(#)mp_session.C 1.84 96/01/10
*
* Tool Talk Message Passer (MP) - mp_session.cc
*
* Copyright (c) 1990,1992 by Sun Microsystems, Inc.
*
* Implementation of the _Tt_session class.
*/
#include "util/tt_global_env.h"
#include "util/tt_xdr_version.h"
#include "util/tt_host.h"
#include "util/tt_port.h"
#include "util/tt_gettext.h"
#include "mp/mp_global.h"
#include "mp/mp_message.h"
#include "mp/mp_mp.h"
#include "mp/mp_c_global.h"
#include "mp/mp_c_session.h"
#include "mp/mp_c_mp.h"
#include "mp/mp_pattern.h"
#include "mp/mp_rpc_client.h"
#include "mp/mp_rpc_interface.h"
#include "mp/mp_session.h"
#include "mp/mp_desktop.h"
#include "mp/mp_xdr_functions.h"
#include <unistd.h>
#ifdef OPT_UNIX_SOCKET_RPC
# include <sys/socket.h>
# include <sys/un.h>
#endif // OPT_UNIX_SOCKET_RPC
_Tt_session::
_Tt_session()
{
_env = _TT_ENV_LAST;
_is_server = 0; // default server mode
_is_dead = 0;
_rpc_version = 0;
}
_Tt_session::
~_Tt_session()
{
if (! _desktop.is_null()) {
if (_is_server && _env == _TT_ENV_X11 && (_id.len() > 0)) {
if ( (! _desktop->del_prop(TT_XATOM_NAME))
|| (! _desktop->del_prop(TT_CDE_XATOM_NAME)))
{
_tt_syslog( 0, LOG_WARNING,
catgets( _ttcatd, 1, 14,
"could not delete the X "
"root window property %s "
"advertising this "
"session" ),
TT_XATOM_NAME );
}
}
}
#ifdef OPT_UNIX_SOCKET_RPC
if (_is_server && _socket_name.len()) {
(void)unlink((char *)_socket_name);
}
#endif
}
#ifdef OPT_UNIX_SOCKET_RPC
//
// Returns the name of the socket file if the unix socket rpc option is
// enabled. Note that the name should be unique for all sessions running
// on the same machine so it has to be derived from the session id
// (which has the required uniqueness properties).
//
char * _Tt_session::
local_socket_name()
{
#define SPRFX "/tmp/.TT"
if (_socket_name.len() == 0) {
char *sname = (char *)malloc(_id.len() + strlen(SPRFX) + 1);
char *sc;
sprintf(sname,"%s%s", SPRFX, (char *)_id);
sc = sname;
while (*sc) {
if (*sc == ' ') {
*sc = '_';
}
sc++;
}
_socket_name = sname;
free((MALLOCTYPE *)sname);
}
return((char *)_socket_name);
}
//
// Opens a connection to the unix socket bound to the given socket name.
// If successful returns the fd for the connection. Otherwise, returns
// -1.
//
int
c_open_unix_socket(char *socket_name)
{
int sock;
struct sockaddr_un server_addr;
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
_tt_syslog( 0, LOG_ERR, "c_open_unix_socket(): socket(): %m" );
return -1;
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sun_family = AF_UNIX;
strcpy(server_addr.sun_path, socket_name);
#if defined(ultrix) || defined(_AIX) || defined(hpux) || defined(__osf__)
int servlen = strlen(server_addr.sun_path) + sizeof(server_addr.sun_fam\
ily);
if (connect(sock, (sockaddr *)&server_addr, servlen) < 0) {
#else
if (connect(sock, (sockaddr *)&server_addr, sizeof(sockaddr_un)) < 0) {
#endif
return(-1);
}
return(sock);
}
#endif // OPT_UNIX_SOCKET_RPC
//
// Called if an event comes in from our desktop connection.
//
int _Tt_session::
desktop_event_callback()
{
if (! _desktop->process_event()) {
return (-1);
}
else
return 0;
}
//
// Initializes a session with the assumption that the server session is
// already running. If the server session isn't running then this method
// will return an error as opposed to attempting to autostart a new
// session (see _Tt_session::c_init). This is intended as a lower-level
// init function used by c_init or whenever autostarting is not required.
//
// Returns:
// TT_OK
// TT_ERR_ACCESS Could not init desktop (diagnostic emitted)
// TT_WRN_NOTFOUND No advertised address
// TT_ERR_INVALID Could not parse advertised address
// TT_ERR_NO_MATCH Advertised address's version is too new
// (diagnostic emitted)
// TT_ERR_ADDRESS Could not find advertised host
// TT_ERR_NOMP Could not init as rpc client
//
Tt_status _Tt_session::
client_session_init()
{
// this is a client of this session. Note that since this
// function may be called in the server, we can't use
// _tt_mp->in_server().
//
Tt_status err;
int rpc_init_done = 0;
_Tt_host_ptr lh;
_is_server = 0;
if (env() == _TT_ENV_X11 && _desktop.is_null()) {
_desktop = new _Tt_desktop();
if (! _desktop->init(_displayname, _TT_DESKTOP_X11)) {
return(TT_ERR_ACCESS);
}
}
if (_address_string.len() == 0) {
if (find_advertised_address(_address_string) != TT_OK) {
return(TT_WRN_NOTFOUND);
}
}
if (_address_string.len() == 0) {
// Don't call parsed_address() with an empty string,
// or it will think we're trying to create an address
// string instead of parse it. parsed_address()
// shouldn't be this cute. XXX
return TT_ERR_INVALID;
}
if ((err = parsed_address(_address_string)) != TT_OK) {
_address_string = (char *)0;
return(err);
}
if (_TT_AUTH_ICEAUTH == _auth.auth_level() &&
(err = _auth.retrieve_auth_cookie()) != TT_OK) {
return err;
}
if (! _tt_global->find_host(_hostaddr, _host, 1)) {
return(TT_ERR_ADDRESS);
}
if (_id.len() == 0) {
(void)set_id();
}
#ifdef OPT_UNIX_SOCKET_RPC
if (_tt_global->get_local_host(lh)) {
// if we are in the same host as the server session
// then we attempt to connect to its advertised unix
// socket to set up an rpc connection. If we succeed
// then we set rpc_init_done to 1 to prevent a normal
// tcp rpc connection from being made.
if (lh->stringaddr() == _host->stringaddr()) {
_u_sock = c_open_unix_socket(local_socket_name());
if (_u_sock != -1) {
_rpc_client = new _Tt_rpc_client(_u_sock);
if (_rpc_client->init(lh, _rpc_program,
_rpc_version,
_server_uid,
&_auth)) {
rpc_init_done = 1;
// Since we opened the fd ourselves,
// clnt_destroy won\'t close it
// unless we tell it it\'s OK.
clnt_control(_rpc_client->rpc_handle(),
CLSET_FD_CLOSE,
(char *) NULL);
}
}
}
}
#endif // OPT_UNIX_SOCKET_RPC
if (! rpc_init_done) {
_rpc_client = new _Tt_rpc_client();
if (! _rpc_client->init(_host, _rpc_program, _rpc_version,
_server_uid, _auth)) {
return(TT_ERR_NOMP);
}
}
// Get and save the file descriptor for this session.
_tt_mp->save_session_fd(_rpc_client->socket());
return(TT_OK);
}
//
// Verifies that the server side of the session is alive and is a
// ToolTalk session. Currently this is done by first invoking rpc
// procedure 0 to see if the session is responding to rpc requests. If
// that succeeds then we invoke rpc procedure TT_RPC_VRFY_SESSION which
// is a reasonably large number. The reply to this procedure should be
// the session id of the session we're talking to. This is a fairly good
// (but not foolproof!) method of verifying that this is a ToolTalk
// session.
//
// In fact it seems to be too picky, if the session id we have is
// different only in the IP address, it may just be an alternate
// IP address for the very same session.
//
// Returns:
// TT_OK
// TT_ERR_NOMP Session unreachable or a hoaxer
// TT_ERR_NO_MATCH Session has wrong version
// TT_ERR_INVALID Could not parse advertised address
// TT_ERR_AUTHORIZATION RPC authorization error
//
Tt_status _Tt_session::
ping()
{
Tt_status is_live;
_Tt_string sid;
// We used to call the NULLPROC here first, but that seems
// to be a waste of a round-trip since it doesn't tell
// us anything that the TT_RPC_VRFY_SESSION call doesn't.
is_live = call((int)TT_RPC_VRFY_SESSION,
(xdrproc_t)xdr_void, 0,
(xdrproc_t)tt_xdr_string,
(char *)&sid);
// We used to string-compare the returned session id with the one we
// have, but that was too picky since the IP address can usefully be
// different. Skip the check for now, perhaps we should check at
// least some of the components (UNIX pid?) We already know the
// transient RPC number is good, and most everything else is
// constant. We do make a minimal check that the id string is non
// null, this might catch the (unlikely) case where the program at
// the other end isn't a ttsession but does happen to have a
// procedure with a number the same as TT_RPC_VRFY_SESSION,
// although in that case I'd expect the RPC to fail in the
// XDR routines.
if (is_live == TT_OK && 0 == sid.len()) {
is_live = TT_ERR_NOMP;
}
if (is_live == TT_ERR_UNIMP) {
is_live = TT_ERR_INTERNAL;
}
// And finally, for reasons I haven't quite figured out,
// if the session id we have *isn't* equal to the one returned
// by ttsession, file scoped messages fail. I suspect
// pattern matching somewhere compares the ids.
// So, if the ttsession thinks its name is different, replace
// our idea of the name with its idea of its name.
if (is_live == TT_OK) {
set_id(sid);
}
return(is_live);
}
//
// Invokes an rpc call named by the rpc_proc parameter on the server
// session and returns any results. If timeout is anything other than -1
// then it will be used as the timeout value. Otherwise a suitable
// timeout value is chosen. If rebind is 1 then a new rpc connection will
// be attempted if this rpc fails.
//
// Returns:
// TT_OK
// TT_ERR_NOMP Could not talk to session
// TT_ERR_VERSION_MISMATCH RPC VERSMISMATCH
// TT_ERR_UNIMP rpc_proc not implemented by session
// TT_ERR_INVALID Could not parse address
// TT_ERR_AUTHORIZATION RPC authorization error
//
Tt_status _Tt_session::
call(int rpc_proc,
xdrproc_t xdr_arg_fn, char *arg,
xdrproc_t xdr_res_fn, char *res,
int timeout, int rebind)
{
//
// Ensure global xdr version is set to proper value for this session.
//
int xdr_version_2_use = _rpc_version;
//
// Some rpc calls use an xdr version number that is greater
// than the version number of the rpc protocol they exist in.
// See e.g. _tt_rpc_add_pattern_with_context().
//
switch (rpc_proc) {
case TT_RPC_ADD_PATTERN_WITH_CONTEXT:
if (xdr_version_2_use < TT_CONTEXTS_XDR_VERSION) {
xdr_version_2_use = TT_CONTEXTS_XDR_VERSION;
}
break;
}
_Tt_xdr_version ver(xdr_version_2_use);
Tt_status status;
clnt_stat rpc_status;
int processing;
int retry;
int tmout;
if (_rpc_client.is_null()) {
return(TT_ERR_INTERNAL);
}
if (timeout == -1) {
switch (rpc_proc) {
case TT_RPC_HDISPATCH:
case TT_RPC_HUPDATE_MSG:
rebind = 1;
/* fall through */
case TT_RPC_DISPATCH_2:
case TT_RPC_DISPATCH_2_WITH_CONTEXT:
case TT_RPC_UPDATE_MSG_2:
case TT_RPC_MSGREAD_2:
tmout = -1;
break;
default:
tmout = TT_RPC_TMOUT;
break;
}
} else {
tmout = timeout;
}
retry = 5;
processing = 1;
status = TT_ERR_NOMP;
while (processing && retry >= 0) {
if (_is_dead) {
// We sometimes hang if we call a dead session
rpc_status = RPC_CANTRECV;
if (! _rpc_client->init(_host, _rpc_program,
_rpc_version,
_server_uid,
_auth)) {
status = TT_ERR_NOMP;
processing = 0;
break;
}
} else {
rpc_status = _rpc_client->call(rpc_proc, xdr_arg_fn,
arg, xdr_res_fn, res,
tmout);
}
switch (rpc_status) {
case RPC_SUCCESS:
status = TT_OK;
processing = 0;
break;
case RPC_CANTRECV:
_is_dead = 1;
status = TT_ERR_NOMP;
retry--;
break;
case RPC_VERSMISMATCH:
case RPC_PROGVERSMISMATCH:
status = TT_ERR_VERSION_MISMATCH;
processing = 0;
break;
case RPC_TIMEDOUT:
if (tmout == 0 || tmout == -1) {
// rpc always returns a timeout error if we're
// in message-passing mode
status = TT_OK;
} else {
// network errors
status = TT_ERR_NOMP;
}
processing = 0;
break;
case RPC_CANTSEND:
if (!rebind) {
status = TT_ERR_NOMP;
retry--;
break;
}
// try to rebind _rpc_client and try again
if (! _rpc_client->init(_host, _rpc_program,
_rpc_version,
_server_uid,
_auth)) {
status = TT_ERR_NOMP;
processing = 0;
break;
}
continue;
case RPC_PROCUNAVAIL:
// We get this if there is a mild version
// mismatch, e.g. a 1.1 library talking to
// a 1.0.x server, and one of the new
// API calls is used. This is relatively
// benign, just let the user know that
// his call is unimplemented in this system
status = TT_ERR_UNIMP;
processing = 0;
break;
case RPC_AUTHERROR:
status = TT_ERR_AUTHORIZATION;
processing = 0;
break;
default:
status = TT_ERR_INTERNAL;
processing = 0;
break;
}
}
if (status == TT_ERR_NOMP &&
!_tt_mp->in_server() &&
!_tt_c_mp->default_c_session.is_null() &&
has_id(_tt_c_mp->default_c_session->address_string())) {
_tt_c_mp->default_c_session = NULL;
}
return(status);
}
//
// Attempts to find the address of the server session. This is done
// according to what kind of environment or session type we're in.
//
Tt_status _Tt_session::
find_advertised_address(_Tt_string &session_addr)
{
switch (env()) {
case _TT_ENV_X11:
if ((! _desktop->get_prop(TT_CDE_XATOM_NAME, session_addr)) &&
(! _desktop->get_prop(TT_XATOM_NAME, session_addr))) {
return(TT_ERR_NOMP);
}
return(TT_OK);
case _TT_ENV_PROCESS_TREE:
if (_address_string.len() == 0) {
session_addr = _tt_get_first_set_env_var(2, TT_CDE_XATOM_NAME, TT_XATOM_NAME);
} else {
session_addr = _address_string;
}
return(TT_OK);
case _TT_ENV_LAST:
default:
return(TT_ERR_NOMP);
}
}
//
// Returns a number indicating what type of session we're in.
//
_Tt_env _Tt_session::
env()
{
if (_tt_mp->in_server()) {
if (_env == _TT_ENV_LAST && getenv("DISPLAY")) {
_env = _TT_ENV_X11;
}
return(_env);
} else if (_env != _TT_ENV_LAST) {
return(_env);
} else {
if (_tt_get_first_set_env_var(2, TT_CDE_XATOM_NAME, TT_XATOM_NAME)) {
return(_env = _TT_ENV_PROCESS_TREE);
} else if (getenv("DISPLAY")) {
return(_env = _TT_ENV_X11);
} else {
return(_TT_ENV_LAST);
}
}
}
//
// Sets the session-type for the session. This affects how the session id
// is advertised to potential clients.
//
void _Tt_session::
set_env(_Tt_env session_env, _Tt_string arg)
{
_env = session_env;
switch (_env) {
case _TT_ENV_X11:
_displayname = arg;
break;
default:
break;
}
}
//
// Returns the ToolTalk session id for the X session named by xdisp. Note
// that no actual contact is attempted.
//
_Tt_string _Tt_session::
Xid(_Tt_string xdisp)
{
return _desktop->session_name(xdisp);
}
/*
void _Tt_session::
print(FILE *fs) const
{
fprintf(fs,"_Tt_session::\n");
}
*/
//
// Used to set or get the address string of a session as well as set
// appropiately the _rpc_version field of the session. If addr_string is
// null, then parsed_address will set the address string of the session.
// In this case, it sets _rpc_version to the default TT_RPC_VERSION. If
// addr_string is not null then parsed_address will attempt to parse the
// string and extract the information in it. In this case, if the
// addr_string happens to be an fcs1 version of session addresses then
// _rpc_version is set to 1, otherwise it is set to TT_RPC_VERSION.
//
// Note that the intended convention for address strings is that only the
// information that is known to this method will be parsed out of them.
// If there is any information beyond that then it is left uninterpreted.
// This means that future ToolTalk versions are free to append
// information to the end of an address string (as is already done
// below) without compromising compatibility with older clients.
//
// Returns:
// TT_OK
// TT_ERR_INVALID Could not parse address
// TT_ERR_NO_MATCH Address version is too new (diagnostic emitted)
//
Tt_status _Tt_session::
parsed_address(_Tt_string &addr_string)
{
#define IPVADDRLEN 16
char session_host[IPVADDRLEN];
char strid[BUFSIZ];
int junk_version = 1;
Tt_status status;
const char *addr_format_fmt = "%%ld %%d %%d %%d %%lu %%%ds %%d";
char addr_format[32];
const char *fcs1_addr_format_fmt = "%%ld %%d %%d %%d %%lu %%%ds";
char fcs1_addr_format[32];
//
// Note: the fcs 1.0 version of tooltalk uses the first 6
// fields in addr_format. Changing these first 6 fields
// compromises binary compatibility with the 1.0 version.
// Additional fields can be added at the end of addr_format as
// long as if the parsing fails then the old format
// (fcs1_addr_format) is tried.
//
_rpc_version = TT_RPC_VERSION;
if (addr_string.len() == 0) {
int ipaddr_len;
// set address string
if (_host.is_null()) {
return(TT_ERR_INTERNAL);
}
if (_host->stringaddr().len() == 0) {
return(TT_ERR_INTERNAL);
}
ipaddr_len = _host->stringaddr().len();
if (ipaddr_len > IPVADDRLEN) ipaddr_len = IPVADDRLEN;
sprintf(fcs1_addr_format, fcs1_addr_format_fmt, ipaddr_len);
sprintf(addr_format, addr_format_fmt, ipaddr_len);
// put version number for format first (this is so we
// can change the format later)
sprintf(strid, "%02d ", _TT_XATOM_VERSION);
sprintf(strid+3, addr_format,
(long)_pid,
_rpc_program,
junk_version,
(int)_auth.auth_level(),
(long)_server_uid,
(char *)_host->stringaddr(),
_rpc_version);
addr_string = strid;
if ((status = _auth.set_sessionid(
_rpc_program,
_auth.auth_level(),
_host->stringaddr(),
_rpc_version)) != TT_OK) {
_tt_syslog(0, LOG_ERR,"_auth.set_sessionid() != TT_OK");
return(status);
}
} else {
// get (parse) address string
char *str = (char *)addr_string;
sprintf(fcs1_addr_format, fcs1_addr_format_fmt, IPVADDRLEN);
sprintf(addr_format, addr_format_fmt, IPVADDRLEN);
// check version number of format first
// XXX: note that if _TT_XATOM_VERSION is ever changed
// then backward compatibility is seriously
// compromised.
if (atoi(str) != _TT_XATOM_VERSION) {
_tt_syslog( 0, LOG_ERR,
catgets( _ttcatd, 1, 15,
"address version is %d, but "
"I only understand %d! (address: "
"<%s>)" ),
atoi(str), _TT_XATOM_VERSION,
addr_string.operator const char *() );
return TT_ERR_NO_MATCH;
}
// XXX: Originally, the fcs1_addr_format put in a
// field describing the rpc version of the server.
// However, the fcs1 version of client_session_init
// erroneously initialized the rpc connection with the
// *server* rpc version rather than its own. Thus we
// can't use the rpc version field in fcs1_addr_format
// because then old fcs1.0 clients would mistakenly
// initialize themselves as version 1+ clients. Thus
// (sigh) we have to add a field at the end of
// fcs1_addr_format that is the real rpc version of
// the server. This is the reason that the first rpc
// version parsed from addr_format is thrown away.
long long_pid;
long long_server_uid;
_Tt_auth_level auth_level;
if (7 != sscanf(str+3, addr_format,
&long_pid,
&_rpc_program,
&junk_version, /* always 1 ... */
&auth_level,
&long_server_uid,
session_host,
&_rpc_version)) {
// new format scan failed. Try to parse the
// string for the old format
if (6 != sscanf(str+3, fcs1_addr_format,
&long_pid,
&_rpc_program,
&_rpc_version,
&auth_level,
&long_server_uid,
session_host)) {
_pid = (pid_t) long_pid;
_server_uid = (uid_t) long_server_uid;
return(TT_ERR_INVALID);
} else {
_rpc_version = 1;
}
}
_pid = (pid_t) long_pid;
_server_uid = (uid_t) long_server_uid;
_hostaddr = session_host;
_auth.set_auth_level(auth_level);
if ((status = _auth.set_sessionid(
_rpc_program,
auth_level,
_hostaddr,
_rpc_version)) != TT_OK) {
_tt_syslog(0, LOG_ERR,"_auth.set_sessionid() != TT_OK");
return(status);
}
}
return(TT_OK);
}
//
// Sets the id of a session. Note that addressing information (the rpc
// number and version) are not part of the id. This makes it possible in
// the future to provide server address rebinding.
//
Tt_status _Tt_session::
set_id(char *id)
{
char host[64];
char dpname[125];
int svnum;
char *ssid;
if (id != (char *)0) {
_id = id;
switch (_id[0]) {
case 'X':
// construct a suitable DISPLAY name from the id
// which should have the format "X <host> <server_num>"
if (sscanf((char *)id, "X %s %d", host, &svnum) != 2) {
return(TT_ERR_SESSION);
}
/* We _cannot_ set _displayname based solely on host and svnum,
* because :0 is NOT the same as 127.0.0.1:0 as far as X11
* is concerned: by default, it will only accept connections
* to the former. (XOpenDisplay etc. will fail if you try the below!)
sprintf(dpname, "%s:%d", host, svnum);
_displayname = dpname;
*/
if (! _displayname.len()) {
_displayname = _tt_global->xdisplayname;
}
_server_num = svnum;
_env = _TT_ENV_X11;
break;
case 'P':
// A process-tree session id is just an address string
// preceded by "P ".
_address_string = _id.mid(2, _id.len());
_env = _TT_ENV_PROCESS_TREE;
break;
default:
return(TT_ERR_SESSION);
}
} else {
// set the "id" which is the publicly visible *logical*
// address of this session.
ssid = _tt_get_first_set_env_var(2, TT_CDE_START_SID, TT_START_SID);
if (ssid != (char *)0) {
_id = ssid;
} else {
switch (env()) {
case _TT_ENV_X11:
_type = "X";
if (! _displayname.len()) {
_displayname = _tt_global->xdisplayname;
}
_id = Xid(_displayname);
break;
case _TT_ENV_PROCESS_TREE:
_type = "P";
_server_num = _pid;
// sami said originally:
// we need to include the address string in
// the id of a process-tree session because
// there is no alternate means of finding
// the address (ie. for X11 the id could be
// rid of address info because the X server
// served as the alternate way of finding
// the address).
// rfm sez, 16 June 94:
// Of course that alternate way was a bad
// idea since it means other users can't
// send messages using the session because
// they can't contact the X server.
_id = process_tree_id();
break;
case _TT_ENV_LAST:
default:
return(TT_ERR_INTERNAL);
}
}
}
return(TT_OK);
}
//
// Returns a process-tree id for this session. This is essentially just
// the address of the session preceded by a "P". The purpose of this is
// that whenever this exact session needs to be advertised to a
// persistent medium (as is done with file-scope messages) this version
// of the session id is used so that if the session goes down and comes
// up again, the session id stored on disk will become stale.
//
_Tt_string _Tt_session::
process_tree_id()
{
_Tt_string result = "P ";
return(result.cat(_address_string));
}
bool_t _Tt_session::
xdr(XDR *xdrs)
{
return(_id.xdr(xdrs) && _address_string.xdr(xdrs));
}
_Tt_string _Tt_session::
address_string()
{
return(_address_string);
}
_Tt_string _Tt_session::
displayname()
{
return(_displayname);
}
_Tt_string
_tt_session_address(_Tt_object_ptr &o)
{
return ((_Tt_session *)o.c_pointer())->address_string();
}
//
// Returns 1 if the given id is the same as the id of this session or if
// it is a process-tree id then it has the same address as this session.
//
int _Tt_session::
has_id(const _Tt_string &id)
{
if (id == _id) {
return(1);
}
if (id.len() == 0) {
return(0);
}
if (id == _address_string) {
return(1);
}
if (id[0] == 'P') {
_Tt_string addr = id.mid(2,id.len());
return(addr == _address_string);
}
return(0);
}
// ...for strings list
int _Tt_session::
has_id(const _Tt_string_list_ptr slist_p)
{
_Tt_string_list_cursor c(slist_p);
while (c.next()) {
if (has_id(*c)) {
return(1);
}
}
return(0);
}