In part of the tooltalk rpc code (mp_message.c), it was assumed that on the majority of platforms, sizeof(uid_t)=sizeof(gid_t)=sizeof(long). On Linux-x64, uid_t is an unsigned int, which makes the code fail: all tooltalk messages fail to send with an RPC_CANTENCODEARGS at the rpc-level, and TT_INTERNAL_ERR for the actual program. We instead change the code to explicitly examine sizeof(uid_t) to see whether it is int or long sized. This allows tooltalk-dependent functinoality like logout and multiple calls to dtfile to work.
1310 lines
30 KiB
C
1310 lines
30 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_message.C /main/4 1998/04/09 17:52:22 mgreess $
|
|
/*
|
|
*
|
|
* @(#)mp_message.C 1.52 93/09/07
|
|
*
|
|
* Tool Talk Message Passer (MP) - mp_message.cc
|
|
*
|
|
* Copyright (c) 1990,1992 by Sun Microsystems, Inc.
|
|
*/
|
|
#include <util/tt_global_env.h>
|
|
// Strictly, mp_message should not include the client-only mp structure.
|
|
// But we have just one client-only call buried in the xdr method,
|
|
// and splitting that out would be too hard (having different xdr
|
|
// methods for the server and the client would be madness!)
|
|
#include <mp/mp_c_global.h>
|
|
#include <mp/mp_c_mp.h>
|
|
#include <mp/mp_arg.h>
|
|
#include <mp/mp_msg_context.h>
|
|
#include <mp/mp_message.h>
|
|
#include <mp/mp_pattern.h>
|
|
#include <mp/mp_procid.h>
|
|
#include <mp/mp_session.h>
|
|
#include <util/tt_enumname.h>
|
|
#include <util/tt_port.h>
|
|
|
|
//
|
|
// Base constructor for a message. ::xdr() relies on this
|
|
// to reset everything because _Tt_s_mp keeps a global
|
|
// _Tt_message as a buffer for reading messages off the wire,
|
|
// instead of constructing a new one each time. XXX I refuse
|
|
// to believe that constructing a new one cannot be made cheap.
|
|
//
|
|
void _Tt_message::
|
|
base_constructor()
|
|
{
|
|
_pattern_id = 0;
|
|
_state = TT_CREATED;
|
|
_status = (int)TT_OK;
|
|
_paradigm = TT_ADDRESS_LAST;
|
|
_scope = TT_SCOPE_NONE;
|
|
_reliability = TT_DISCARD;
|
|
_opnum = -1;
|
|
_object = 0;
|
|
_file = 0;
|
|
_op = 0;
|
|
_otype = 0;
|
|
_session = 0;
|
|
_sender = 0;
|
|
_handler = 0;
|
|
_abstainers = 0;
|
|
_accepters = 0;
|
|
_rejecters = 0;
|
|
_sender_ptype = 0;
|
|
_handler_ptype = 0;
|
|
_rsessions = 0;
|
|
_id = 0;
|
|
_api_id = 0;
|
|
_args = new _Tt_arg_list;
|
|
_out_args = 0;
|
|
_contexts = new _Tt_msg_context_list;
|
|
_flags = 0;
|
|
_ptr_guards = 0;
|
|
_gid = _tt_global->gid;
|
|
_uid = _tt_global->uid;
|
|
// Set the default set of fields to be sent by
|
|
// _Tt_message::xdr. Note that it is important for
|
|
// _TT_MSK_PARADIGM and _TT_MSK_STATE to be part of this set
|
|
// (see relevant comments in _Tt_message::xdr).
|
|
_full_msg_guards = (_TT_MSK_ID |
|
|
_TT_MSK_MESSAGE_CLASS |
|
|
_TT_MSK_STATE |
|
|
_TT_MSK_PARADIGM |
|
|
_TT_MSK_SCOPE |
|
|
_TT_MSK_UID |
|
|
_TT_MSK_GID |
|
|
_TT_MSK_STATUS |
|
|
_TT_MSK_FLAGS);
|
|
_message_class = TT_CLASS_UNDEFINED;
|
|
_status_string = 0;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Default constructor.
|
|
//
|
|
|
|
// XXX: Make sure all _Tt_strings do *not* point to
|
|
// _tt_global->universal_null_string for messages,
|
|
// because otherwise svc_getargs will clobber the
|
|
// global data
|
|
|
|
_Tt_message::
|
|
_Tt_message()
|
|
#if defined(linux) || defined(CSRG_BASED)
|
|
: _pattern_id(), _object(), _file(), _op(),
|
|
_otype(), _sender_ptype(), _handler_ptype(),
|
|
_api_id(), _status_string()
|
|
#else
|
|
: _pattern_id(NULL), _object(NULL), _file(NULL), _op(NULL),
|
|
_otype(NULL), _sender_ptype(NULL), _handler_ptype(NULL),
|
|
_api_id(NULL), _status_string(NULL)
|
|
#endif
|
|
{
|
|
base_constructor();
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Destroys a message object.
|
|
//
|
|
_Tt_message::
|
|
~_Tt_message()
|
|
{
|
|
// note _sender and _handler may be circular references
|
|
// so we explicitly set them to 0 to produce any garbage
|
|
// collection.
|
|
_sender = (_Tt_procid *)0;
|
|
_handler = (_Tt_procid *)0;
|
|
_session = (_Tt_session *)0;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Returns 1 if m is equal to this message. Message equality can be
|
|
// determined by logically concatenating the message sender with the
|
|
// message id.
|
|
//
|
|
int _Tt_message::
|
|
is_equal(const _Tt_message_ptr &m)
|
|
{
|
|
if (m->_id != _id) {
|
|
return(0);
|
|
}
|
|
if (m->_sender.is_null() && _sender.is_null()) {
|
|
return(1);
|
|
} else if (m->_sender.is_null() || _sender.is_null()) {
|
|
return(0);
|
|
} else {
|
|
return(m->_sender->id() == _sender->id());
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// XDR encodes/decodes a message.
|
|
//
|
|
// Because xdr'ing a message is crucial to the message-passing
|
|
// performance the way messages are xdr'ed is a little more complicated
|
|
// than other xdr methods.
|
|
//
|
|
// The main optimization that is done is to have an integer field,
|
|
// _ptr_guards, is a collection of bit fields. If a particular bit is
|
|
// turned on then this means that the corresponding message field is
|
|
// being sent/received from the xdr stream. These bit fields obey the
|
|
// following naming convention, if _ptr_guards&_TT_MSK_<field> is true
|
|
// then <field> is being sent/received from the xdr stream. Note that
|
|
// this means that this optimization can only apply to at most 32
|
|
// fields.
|
|
//
|
|
// This scheme is an optimization if it allows us to send less
|
|
// information for a given message. The way it does this is by allowing
|
|
// "default" values to not be sent. For example, if a typical value of
|
|
// the _scope field is TT_SESSION then rather than send this value every
|
|
// time, we just leave the bit turned off and have the other end just use
|
|
// the default value if it notices the bit is turned off. Another way
|
|
// we can avoid sending the entire message is if it is known that
|
|
// certain fields won't be required. For example, when a handler
|
|
// replies to a message, it is unnecessary to send back the entire
|
|
// list of arguments since, by definition, only the TT_OUT and
|
|
// TT_INOUT arguments can change.
|
|
//
|
|
// There are certain methods that are called just before a message is
|
|
// going to be xdr'ed that set up the _ptr_guards field to turn on the
|
|
// proper set of flags. These methods are:
|
|
//
|
|
// _Tt_c_message::set_return_handler_flags
|
|
//
|
|
// Optimizes message xdr for the case of a handler replying to a
|
|
// message.
|
|
//
|
|
// _Tt_s_message::set_return_sender_flags
|
|
//
|
|
// Optimizes message xdr for the case of a message being returned
|
|
// to its original sender.
|
|
//
|
|
// _Tt_s_message::set_send_handler_flags
|
|
//
|
|
// Optimizes message xdr for the case of sending a message to a
|
|
// handler.
|
|
//
|
|
// The way these methods work is by setting the _ptr_guards field to some
|
|
// value other than 0 that has the proper flag bits turned on. Then this
|
|
// method checks for _ptr_guards being 0. If it is then it just uses the
|
|
// value of _full_msg_guards which is an always up-to-date set of flags
|
|
// of message fields that need to get xdr'ed in the default case. If
|
|
// _ptr_guards is not 0 then that value gets used instead of the default.
|
|
// Another detail of this mechanism is that the _flags field may
|
|
// sometimes have the _TT_MSG_UPDATE_XDR_MODE flag turned on. If this is
|
|
// the case then this indicates that when encoding the message only the
|
|
// arguments contained in the _out_args list are to be used rather than
|
|
// the ones in the _args list. This is because the args in _out_args are
|
|
// only the TT_OUT and TT_INOUT arguments.
|
|
//
|
|
bool_t _Tt_message::
|
|
xdr(XDR *xdrs)
|
|
{
|
|
if (xdrs->x_op == XDR_DECODE) {
|
|
base_constructor();
|
|
}
|
|
if (xdrs->x_op == XDR_ENCODE && _ptr_guards==0) {
|
|
_flags &= ~(1<<_TT_MSG_UPDATE_XDR_MODE);
|
|
_ptr_guards = _full_msg_guards;
|
|
}
|
|
|
|
|
|
if (! xdr_int(xdrs, &_ptr_guards)) {
|
|
return(0);
|
|
}
|
|
int id_2_set;
|
|
int need_2_set_id = 0;
|
|
if (_ptr_guards&_TT_MSK_ID) {
|
|
if (xdrs->x_op == XDR_DECODE) {
|
|
need_2_set_id = 1;
|
|
if (! xdr_int(xdrs, &id_2_set)) {
|
|
return(0);
|
|
}
|
|
} else {
|
|
if (! xdr_int(xdrs, &_id)) {
|
|
return(0);
|
|
}
|
|
}
|
|
}
|
|
if (_ptr_guards&_TT_MSK_MESSAGE_CLASS) {
|
|
if (! xdr_int(xdrs, (int *)&_message_class)) {
|
|
return(0);
|
|
}
|
|
}
|
|
if (_ptr_guards&_TT_MSK_STATE) {
|
|
if (! xdr_int(xdrs, (int *)&_state)) {
|
|
return(0);
|
|
}
|
|
} else { // XXXX only if XDR_DECODE, right? et al!
|
|
_state = TT_SENT;
|
|
}
|
|
if (_ptr_guards&_TT_MSK_PARADIGM) {
|
|
if (! xdr_int(xdrs, (int *)&_paradigm)) {
|
|
return(0);
|
|
}
|
|
}
|
|
if (_ptr_guards&_TT_MSK_SCOPE) {
|
|
if (! xdr_int(xdrs, (int *)&_scope)) {
|
|
return(0);
|
|
}
|
|
} else if (_tt_global->xdr_version() > 1) {
|
|
_scope = TT_SESSION;
|
|
}
|
|
if (_ptr_guards&_TT_MSK_RELIABILITY) {
|
|
if (! xdr_int(xdrs, (int *)&_reliability)) {
|
|
return(0);
|
|
}
|
|
}
|
|
if (_ptr_guards&_TT_MSK_OPNUM) {
|
|
if (! xdr_int(xdrs, &_opnum)) {
|
|
return(0);
|
|
}
|
|
}
|
|
if (_ptr_guards&_TT_MSK_STATUS) {
|
|
if (! xdr_int(xdrs,&_status)) {
|
|
return(0);
|
|
}
|
|
}
|
|
// Even though in Solaris 2.x uid_t and gid_t are typedef'd as
|
|
// u_long, the compiler complains if they are not explicitly
|
|
// coerced.
|
|
|
|
/*
|
|
* Obviously there is no xdr_u_uid_t, so we have to hack around this.
|
|
* At least by using sizeof checks, we aren't manually specifying
|
|
* the size of uid_t depending on the platform (which broke terribly
|
|
* when we tried to port to 64-bit linux at first).
|
|
*
|
|
* A side-effect of testing this way is that we have to spell out the pointer
|
|
* casts, since one of them is actually wrong for any given platform (but
|
|
* is also a dead code branch)
|
|
*/
|
|
if (_ptr_guards&_TT_MSK_UID) {
|
|
if (xdrs->x_op == XDR_DECODE) {
|
|
_uid = 0;
|
|
}
|
|
if (sizeof (int) == sizeof(uid_t)) {
|
|
if (! xdr_u_int(xdrs,(u_int *) &_uid)) return 0;
|
|
} else if (sizeof (long) == sizeof(uid_t)) {
|
|
if (! xdr_u_long(xdrs,(u_long *) &_gid)) return 0;
|
|
} else {
|
|
_tt_syslog( 0, LOG_ERR, "_Tt_message::xdr(XDR*): uid_t size is not equal to int or long; TOOLTALK RPC WILL NOT WORK!" );
|
|
}
|
|
}
|
|
if (_ptr_guards&_TT_MSK_GID) {
|
|
if (xdrs->x_op == XDR_DECODE) {
|
|
_gid = 0;
|
|
}
|
|
if (sizeof (int) == sizeof(gid_t)) {
|
|
if (! xdr_u_int(xdrs,(u_int *) &_gid)) {
|
|
return(0);
|
|
}
|
|
} else if (sizeof (long) == sizeof(gid_t)) {
|
|
if (! xdr_u_long(xdrs,(u_long *) &_gid)) {
|
|
return(0);
|
|
}
|
|
} else {
|
|
_tt_syslog( 0, LOG_ERR, "_Tt_message::xdr(XDR*): gid_t size is not equal to int or long; TOOLTALK RPC WILL NOT WORK!" );
|
|
}
|
|
}
|
|
|
|
if (_ptr_guards&_TT_MSK_SESSION) {
|
|
if (xdrs->x_op == XDR_DECODE) {
|
|
_session = new _Tt_session();
|
|
}
|
|
if (! _session->xdr(xdrs)) {
|
|
return(0);
|
|
}
|
|
} else if (xdrs->x_op == XDR_DECODE) {
|
|
_session = _tt_mp->initial_session;
|
|
}
|
|
|
|
if (_ptr_guards&_TT_MSK_SENDER) {
|
|
if (xdrs->x_op == XDR_DECODE) {
|
|
_sender = new _Tt_procid();
|
|
}
|
|
if (! _sender->xdr(xdrs)) {
|
|
return(0);
|
|
}
|
|
} else if (! _tt_mp->in_server()) {
|
|
// Since we know we're not in the server, we know that
|
|
// _tt_c_mp is valid.
|
|
_sender = _tt_c_mp->default_procid();
|
|
}
|
|
// _set_id() only works if _handler is set
|
|
if (need_2_set_id) {
|
|
_set_id(id_2_set);
|
|
}
|
|
|
|
|
|
switch (_tt_global->xdr_version()) {
|
|
case 1:
|
|
// version 1 tooltalk always xdr's a _Tt_procid_ptr
|
|
if (! _handler.xdr(xdrs)) {
|
|
return(0);
|
|
}
|
|
break;
|
|
case 2:
|
|
default:
|
|
if (xdrs->x_op == XDR_DECODE) {
|
|
//
|
|
// XXX holtz: Also do this for other fields?
|
|
// If not, *this is a hybrid message that
|
|
// is dangerous to look at until you use it
|
|
// to update_message().
|
|
//
|
|
_handler = 0;
|
|
}
|
|
if (_ptr_guards&_TT_MSK_HANDLER) {
|
|
if (xdrs->x_op == XDR_DECODE) {
|
|
_handler = new _Tt_procid();
|
|
}
|
|
if (! _handler->xdr(xdrs)) {
|
|
return(0);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
if (_ptr_guards&_TT_MSK_FILE) {
|
|
if (! _file->xdr(xdrs)) {
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
if (_ptr_guards&_TT_MSK_OBJECT) {
|
|
if (! _object->xdr(xdrs)) {
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
if (_ptr_guards&_TT_MSK_OP) {
|
|
if (! _op->xdr(xdrs)) {
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
if (_ptr_guards&_TT_MSK_ARGS) {
|
|
if (xdrs->x_op == XDR_ENCODE) {
|
|
if (_flags&(1<<_TT_MSG_UPDATE_XDR_MODE)) {
|
|
|
|
// if this flag is turned on then only
|
|
// send arguments from the _out_args
|
|
// field rather than the _args field.
|
|
|
|
if (_out_args.is_null()) {
|
|
_out_args = new _Tt_arg_list();
|
|
}
|
|
if (! _out_args->xdr(xdrs)) {
|
|
return(0);
|
|
}
|
|
} else {
|
|
if (! _args->xdr(xdrs)) {
|
|
return(0);
|
|
}
|
|
}
|
|
} else {
|
|
_args->flush();
|
|
SET_GUARD(_full_msg_guards, 0, _TT_MSK_ARGS);
|
|
|
|
if (! _args->xdr(xdrs)) {
|
|
return(0);
|
|
}
|
|
}
|
|
}
|
|
if (_ptr_guards&_TT_MSK_FLAGS) {
|
|
if (! xdr_int(xdrs, &_flags)) {
|
|
return(0);
|
|
}
|
|
if (xdrs->x_op == XDR_DECODE) {
|
|
// Assume non-remote, until we learn otherwise
|
|
_flags &= ~(1<<_TT_MSG_IS_REMOTE);
|
|
}
|
|
}
|
|
if (_ptr_guards&_TT_MSK_OTYPE) {
|
|
if (! _otype->xdr(xdrs)) {
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
if (_ptr_guards&_TT_MSK_SENDER_PTYPE) {
|
|
if (! _sender_ptype->xdr(xdrs)) {
|
|
return(0);
|
|
}
|
|
}
|
|
if (_ptr_guards&_TT_MSK_HANDLER_PTYPE) {
|
|
if (! _handler_ptype->xdr(xdrs)) {
|
|
return(0);
|
|
}
|
|
}
|
|
if (_ptr_guards&_TT_MSK_PATTERN_ID) {
|
|
if (! _pattern_id->xdr(xdrs)) {
|
|
return(0);
|
|
}
|
|
}
|
|
if (_ptr_guards&_TT_MSK_RSESSIONS) {
|
|
if (xdrs->x_op == XDR_DECODE) {
|
|
_rsessions = new _Tt_string_list();
|
|
}
|
|
if (! _rsessions->xdr(xdrs)) {
|
|
return(0);
|
|
}
|
|
}
|
|
if (_ptr_guards&_TT_MSK_STATUS_STRING) {
|
|
if (! _status_string->xdr(xdrs)) {
|
|
return(0);
|
|
}
|
|
}
|
|
//
|
|
// Because of the bitmask, we don't worry about
|
|
// xdr versioning here, and in effect pretend that
|
|
// _TT_MSK_CONTEXTS has been defined from day 1.
|
|
//
|
|
if (_ptr_guards&_TT_MSK_CONTEXTS) {
|
|
if (! _contexts->xdr(xdrs)) {
|
|
return(0);
|
|
}
|
|
}
|
|
//
|
|
// Ditto.
|
|
//
|
|
if (_ptr_guards&_TT_MSK_OFFEREES) {
|
|
//
|
|
// TT_OFFERS are more rare than contexts, so
|
|
// we allocate the lists lazily to save memory.
|
|
//
|
|
if (_abstainers.is_null()) {
|
|
_abstainers = new _Tt_procid_list;
|
|
}
|
|
if (! _abstainers->xdr(xdrs)) {
|
|
return(0);
|
|
}
|
|
if (_accepters.is_null()) {
|
|
_accepters = new _Tt_procid_list;
|
|
}
|
|
if (! _accepters->xdr(xdrs)) {
|
|
return(0);
|
|
}
|
|
if (_rejecters.is_null()) {
|
|
_rejecters = new _Tt_procid_list;
|
|
}
|
|
if (! _rejecters->xdr(xdrs)) {
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
if (xdrs->x_op == XDR_DECODE) {
|
|
// Now we want to update _full_msg_guards from
|
|
// _ptr_guards appropiately. We must choose to do this
|
|
// either by assignment or by or'ing the fields.
|
|
// Assignment is required if this is a new message
|
|
// because _full_msg_guards may contain fields that
|
|
// are 1 when they need to be 0 (see
|
|
// _Tt_message::_Tt_message). (and or'ing won't
|
|
// help). We can tell that the message coming in is a
|
|
// new message by checking whether the paradigm and
|
|
// state field is being sent. This is a gross hack but
|
|
// unfortunately when the need for it was discovered
|
|
// there was no other way to test for this in a
|
|
// binary-compatible way with previous versions. Note
|
|
// that the paradigm (known as "address" in the
|
|
// documentation) doesn't ever change once its been
|
|
// created so it should never be the case that sending
|
|
// the message to a recipient in other than the
|
|
// defualt xdr mode should require sending the
|
|
// paradigm field.
|
|
|
|
if (_ptr_guards&(_TT_MSK_PARADIGM|_TT_MSK_STATE)) {
|
|
_full_msg_guards = _ptr_guards;
|
|
} else {
|
|
_full_msg_guards |= _ptr_guards;
|
|
}
|
|
}
|
|
|
|
_ptr_guards = 0;
|
|
return(1);
|
|
}
|
|
|
|
|
|
//
|
|
// m represents the same message as this but perhaps with updated
|
|
// information. This method handles updating this message with the
|
|
// appropiate values in m.
|
|
//
|
|
void _Tt_message::
|
|
update_message(const _Tt_message_ptr &m)
|
|
{
|
|
int margc;
|
|
int mguards = m->_full_msg_guards;
|
|
|
|
_full_msg_guards |= mguards;
|
|
if (!_tt_mp->in_server()) {
|
|
if (mguards&_TT_MSK_STATE) {
|
|
set_state(m->_state);
|
|
}
|
|
if (mguards&_TT_MSK_RELIABILITY) {
|
|
set_reliability(m->_reliability);
|
|
}
|
|
switch (_paradigm) {
|
|
case TT_OBJECT:
|
|
case TT_OTYPE:
|
|
if (mguards&_TT_MSK_SCOPE) {
|
|
_scope = m->_scope;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (mguards&_TT_MSK_PATTERN_ID) {
|
|
if (m->_pattern_id.len()) {
|
|
_pattern_id = m->_pattern_id;
|
|
}
|
|
}
|
|
if (mguards&_TT_MSK_HANDLER) {
|
|
_handler = m->_handler;
|
|
}
|
|
if (mguards&_TT_MSK_HANDLER_PTYPE) {
|
|
_handler_ptype = m->_handler_ptype;
|
|
}
|
|
if (mguards&_TT_MSK_OPNUM) {
|
|
set_opnum(m->opnum());
|
|
}
|
|
}
|
|
if (mguards&_TT_MSK_STATUS) {
|
|
_status = m->_status;
|
|
}
|
|
if (mguards & _TT_MSK_STATUS_STRING) {
|
|
set_status_string(m->_status_string);
|
|
}
|
|
if (mguards & _TT_MSK_OFFEREES) {
|
|
//
|
|
// We could just snare references and share the lists,
|
|
// but if the given message is ttsession's static
|
|
// wire buffer, then the lists will probably be changing.
|
|
//
|
|
_abstainers = new _Tt_procid_list( *m->_abstainers );
|
|
_accepters = new _Tt_procid_list( *m->_accepters );
|
|
_rejecters = new _Tt_procid_list( *m->_rejecters );
|
|
}
|
|
switch (m->_state) {
|
|
case TT_HANDLED:
|
|
case TT_FAILED:
|
|
//
|
|
// update object and file
|
|
//
|
|
|
|
if (mguards&_TT_MSK_OBJECT) {
|
|
_object = m->_object;
|
|
}
|
|
if (mguards&_TT_MSK_FILE) {
|
|
_file = m->_file;
|
|
}
|
|
if (mguards&_TT_MSK_CONTEXTS) {
|
|
// All contexts are INOUT, and extra can
|
|
// be added by the handler.
|
|
_contexts = new _Tt_msg_context_list( *m->_contexts );
|
|
}
|
|
if (mguards&_TT_MSK_ARGS) {
|
|
margc = _args->count();
|
|
if (margc && m->_args->count()) {
|
|
|
|
//
|
|
// update arguments with new values
|
|
//
|
|
|
|
_Tt_arg_list_cursor argc;
|
|
_Tt_arg_list_cursor nargc;
|
|
|
|
argc.reset(_args);
|
|
nargc.reset(m->_args);
|
|
while (argc.next()) {
|
|
switch (argc->mode()) {
|
|
case TT_OUT:
|
|
case TT_INOUT:
|
|
if (nargc.next()) {
|
|
argc->update_value(*nargc);
|
|
nargc.remove();
|
|
}
|
|
break;
|
|
default:
|
|
if (!_tt_mp->in_server() &&
|
|
_message_class==TT_NOTICE &&
|
|
!nargc.next()) {
|
|
m->_full_msg_guards = 0;
|
|
m->_args->flush();
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// fall through
|
|
case TT_RETURNED:
|
|
if (is_awaiting_reply()) {
|
|
set_awaiting_reply( 0 );
|
|
}
|
|
break;
|
|
}
|
|
m->_full_msg_guards = 0;
|
|
// XXX holtz 20 Jul 94 Why change given message?
|
|
m->_args->flush();
|
|
}
|
|
|
|
_Tt_msg_context_ptr _Tt_message::
|
|
context(const char *slotname) const
|
|
{
|
|
_Tt_msg_context_list_cursor contextC( _contexts );
|
|
while (contextC.next()) {
|
|
if (contextC->slotName() == slotname) {
|
|
return *contextC;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
_Tt_msg_context_ptr _Tt_message::
|
|
context(int i) const
|
|
{
|
|
if ((i >= 0) && (i < _contexts->count())) {
|
|
return (*_contexts)[ i ];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int _Tt_message::
|
|
contextsCount() const
|
|
{
|
|
if (_contexts.is_null()) {
|
|
return 0;
|
|
}
|
|
return _contexts->count();
|
|
}
|
|
|
|
|
|
//
|
|
// Returns the id of the pattern that matched this message (ie. that
|
|
// caused it to be delivered). This id will be null if the message
|
|
// matched a ptype pattern rather than a dynamic pattern.
|
|
//
|
|
_Tt_string & _Tt_message::
|
|
pattern_id()
|
|
{
|
|
return(_pattern_id);
|
|
}
|
|
|
|
|
|
//
|
|
// Sets the pattern id of a messsage and turns on the corresponding bit
|
|
// field in _full_msg_guards if non-empty.
|
|
//
|
|
void _Tt_message::
|
|
set_pattern_id(_Tt_string id)
|
|
{
|
|
_pattern_id = id;
|
|
SET_GUARD(_full_msg_guards, _pattern_id.len(), _TT_MSK_PATTERN_ID);
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Function wrapper used to invoke the xdr method on a message when
|
|
// interfacing to the C RPC routines.
|
|
//
|
|
bool_t
|
|
tt_xdr_message(XDR *xdrs, _Tt_message_ptr *msgp)
|
|
{
|
|
return((*msgp).xdr(xdrs));
|
|
}
|
|
|
|
|
|
uid_t _Tt_message::
|
|
uid() const
|
|
{
|
|
return _uid;
|
|
}
|
|
|
|
|
|
gid_t _Tt_message::
|
|
gid() const
|
|
{
|
|
return _gid;
|
|
}
|
|
|
|
|
|
int _Tt_message::
|
|
id() const
|
|
{
|
|
return(_id);
|
|
}
|
|
|
|
const _Tt_string & _Tt_message::
|
|
api_id() const
|
|
{
|
|
return _api_id;
|
|
}
|
|
|
|
|
|
Tt_status _Tt_message::
|
|
set_message_class(Tt_class mclass)
|
|
{
|
|
_message_class = mclass;
|
|
return(TT_OK);
|
|
}
|
|
|
|
|
|
Tt_status _Tt_message::
|
|
set_state(Tt_state state)
|
|
{
|
|
_state = state;
|
|
|
|
return(TT_OK);
|
|
}
|
|
|
|
|
|
Tt_status _Tt_message::
|
|
set_paradigm(Tt_address p)
|
|
{
|
|
_paradigm = p;
|
|
|
|
return(TT_OK);
|
|
}
|
|
|
|
|
|
//
|
|
// Sets the scope of a message. Note that if we're a post-version-1
|
|
// client then we also turn on the corresponding flag in _full_msg_guards
|
|
// if this is a non-TT_SESSION scope.
|
|
//
|
|
Tt_status _Tt_message::
|
|
set_scope(Tt_scope s)
|
|
{
|
|
|
|
// XXX: The xdr_version() only shadows to the sessions xdr version when an
|
|
// RPC call is in progress. set_scope() can be called by
|
|
// tt_message_scope_set() at which time the xdr version is not setup
|
|
// correctly.
|
|
|
|
_scope = s;
|
|
SET_GUARD(_full_msg_guards,1,_TT_MSK_SCOPE);
|
|
return(TT_OK);
|
|
}
|
|
|
|
|
|
//
|
|
// Sets the file field of a message and turn on the corresponding bit in
|
|
// _full_msg_guards if non-empty.
|
|
//
|
|
Tt_status _Tt_message::
|
|
set_file(_Tt_string f)
|
|
{
|
|
if (f.len() == 0) {
|
|
return(TT_OK);
|
|
}
|
|
_file = f;
|
|
SET_GUARD(_full_msg_guards, 1, _TT_MSK_FILE);
|
|
return(TT_OK);
|
|
}
|
|
|
|
|
|
//
|
|
// Sets the session field in a message and turns on the corresponding bit
|
|
// field in _full_msg_guards if non-null.
|
|
//
|
|
Tt_status _Tt_message::
|
|
set_session(_Tt_session_ptr &s)
|
|
{
|
|
_session = s;
|
|
SET_GUARD(_full_msg_guards,(! _session.is_null()), _TT_MSK_SESSION);
|
|
|
|
return(TT_OK);
|
|
}
|
|
|
|
|
|
//
|
|
// Sets the op field in a message and turns on the corresponding bit
|
|
// field in _full_msg_guards if non-null.
|
|
//
|
|
Tt_status _Tt_message::
|
|
set_op(_Tt_string o)
|
|
{
|
|
_op = o;
|
|
SET_GUARD(_full_msg_guards, _op.len(), _TT_MSK_OP);
|
|
|
|
return(TT_OK);
|
|
}
|
|
|
|
|
|
//
|
|
// Sets the opnum field in a message and turns on the corresponding
|
|
// bit field in _full_msg_guards if not equal to -1 (the default).
|
|
//
|
|
Tt_status _Tt_message::
|
|
set_opnum(int o)
|
|
{
|
|
_opnum = o;
|
|
SET_GUARD(_full_msg_guards, _opnum != -1, _TT_MSK_OPNUM);
|
|
|
|
return(TT_OK);
|
|
}
|
|
|
|
|
|
//
|
|
// Adds an argument to a message. Turns on the bit field for _args in
|
|
// _full_msg_guards since we know the list is non-empty.
|
|
//
|
|
Tt_status _Tt_message::
|
|
add_arg(_Tt_arg_ptr &arg)
|
|
{
|
|
_args->append(arg);
|
|
|
|
SET_GUARD(_full_msg_guards, 1, _TT_MSK_ARGS);
|
|
return(TT_OK);
|
|
}
|
|
|
|
|
|
//
|
|
// Adds a TT_OUT or TT_INOUT argument to the _out_args list. This is used
|
|
// by _Tt_message::xdr when the _TT_MSG_UPDATE_XDR flag is turned on.
|
|
//
|
|
void _Tt_message::
|
|
add_out_arg(_Tt_arg_ptr &arg)
|
|
{
|
|
if (_out_args.is_null()) {
|
|
_out_args = new _Tt_arg_list();
|
|
}
|
|
switch (arg->mode()) {
|
|
case TT_OUT:
|
|
case TT_INOUT:
|
|
// a parallel list of just out arguments is kept since
|
|
// whenever it is known that the receiver of a message
|
|
// is only seeing an update of the message, only the
|
|
// out arguments need to be sent.
|
|
_out_args->append(arg);
|
|
SET_GUARD(_full_msg_guards, 1, _TT_MSK_ARGS);
|
|
break;
|
|
case TT_IN:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Adds a context to a message. Turns on the bit field for _contexts in
|
|
// _full_msg_guards since we know the list is non-empty.
|
|
//
|
|
Tt_status _Tt_message::
|
|
add_context(_Tt_msg_context_ptr &context)
|
|
{
|
|
_contexts->append_ordered(context);
|
|
|
|
SET_GUARD(_full_msg_guards, 1, _TT_MSK_CONTEXTS);
|
|
return(TT_OK);
|
|
}
|
|
|
|
|
|
//
|
|
// Sets the object field in a message and turns on the corresponding bit
|
|
// field in _full_msg_guards.
|
|
//
|
|
Tt_status _Tt_message::
|
|
set_object(_Tt_string oid)
|
|
{
|
|
_object = oid;
|
|
SET_GUARD(_full_msg_guards, _object.len(), _TT_MSK_OBJECT);
|
|
return(TT_OK);
|
|
}
|
|
|
|
|
|
Tt_status _Tt_message::
|
|
set_otype(_Tt_string ot)
|
|
{
|
|
_otype = ot;
|
|
SET_GUARD(_full_msg_guards, _otype.len(), _TT_MSK_OTYPE);
|
|
|
|
return(TT_OK);
|
|
}
|
|
|
|
|
|
Tt_status _Tt_message::
|
|
set_sender(_Tt_procid_ptr &s)
|
|
{
|
|
_sender = s;
|
|
SET_GUARD(_full_msg_guards, (! _sender.is_null()), _TT_MSK_SENDER);
|
|
|
|
return(TT_OK);
|
|
}
|
|
|
|
|
|
Tt_status _Tt_message::
|
|
unset_handler_procid(void)
|
|
{
|
|
_handler = (_Tt_procid *) 0;
|
|
SET_GUARD(_full_msg_guards, 0, _TT_MSK_HANDLER);
|
|
|
|
return(TT_OK);
|
|
}
|
|
|
|
Tt_status _Tt_message::
|
|
set_handler_procid(const _Tt_procid_ptr &h)
|
|
{
|
|
_handler = h;
|
|
SET_GUARD(_full_msg_guards, (! _handler.is_null()), _TT_MSK_HANDLER);
|
|
|
|
return(TT_OK);
|
|
}
|
|
|
|
|
|
Tt_status _Tt_message::
|
|
add_voter(const _Tt_procid_ptr &voter, Tt_state vote)
|
|
{
|
|
if (voter.is_null() || (_message_class != TT_OFFER)) {
|
|
return TT_OK;
|
|
}
|
|
if (_abstainers.is_null()) {
|
|
_abstainers = new _Tt_procid_list;
|
|
}
|
|
if (_abstainers.is_null()) {
|
|
return TT_ERR_NOMEM;
|
|
}
|
|
if (_accepters.is_null()) {
|
|
_accepters = new _Tt_procid_list;
|
|
}
|
|
if (_accepters.is_null()) {
|
|
return TT_ERR_NOMEM;
|
|
}
|
|
if (_rejecters.is_null()) {
|
|
_rejecters = new _Tt_procid_list;
|
|
}
|
|
if (_rejecters.is_null()) {
|
|
return TT_ERR_NOMEM;
|
|
}
|
|
switch (vote) {
|
|
case TT_ACCEPTED:
|
|
_accepters->append( voter );
|
|
break;
|
|
case TT_REJECTED:
|
|
_rejecters->append( voter );
|
|
break;
|
|
case TT_ABSTAINED:
|
|
_abstainers->append( voter );
|
|
break;
|
|
default:
|
|
// Not a vote; bail out.
|
|
return TT_OK;
|
|
}
|
|
SET_GUARD(_full_msg_guards, 1, _TT_MSK_OFFEREES);
|
|
return TT_OK;
|
|
}
|
|
|
|
|
|
Tt_status _Tt_message::
|
|
set_sender_ptype(_Tt_string s)
|
|
{
|
|
_sender_ptype = s;
|
|
SET_GUARD(_full_msg_guards,_sender_ptype.len(), _TT_MSK_SENDER_PTYPE);
|
|
|
|
return(TT_OK);
|
|
}
|
|
|
|
|
|
Tt_status _Tt_message::
|
|
set_handler_ptype(_Tt_string h)
|
|
{
|
|
_handler_ptype = h;
|
|
SET_GUARD(_full_msg_guards,_handler_ptype.len(),_TT_MSK_HANDLER_PTYPE);
|
|
|
|
return(TT_OK);
|
|
}
|
|
|
|
|
|
Tt_status _Tt_message::
|
|
set_reliability(Tt_disposition r)
|
|
{
|
|
_reliability = r;
|
|
SET_GUARD(_full_msg_guards, _reliability != TT_DISCARD,
|
|
_TT_MSK_RELIABILITY);
|
|
|
|
return(TT_OK);
|
|
}
|
|
|
|
|
|
//
|
|
// Sets the id of a message which is used to uniquely identify the
|
|
// message within the sending process. The id is also used when queueing
|
|
// the message. This implies that the message contains enough
|
|
// information that is unique so that the queued message will never be
|
|
// misinterpreted to be another message. This uniqueness is achieved by
|
|
// combining the sender procid with the message id. This works because
|
|
// the prefix of the sender procid is unique and the message id then
|
|
// distinguishes the message among other messages the process has sent.
|
|
//
|
|
Tt_status _Tt_message::
|
|
set_id()
|
|
{
|
|
return _set_id(_tt_mp->generate_message_id());
|
|
}
|
|
|
|
Tt_status _Tt_message::
|
|
_set_id(int id)
|
|
{
|
|
_id = id;
|
|
char buf[BUFSIZ];
|
|
sprintf( buf, "%d ", _id );
|
|
_api_id = buf;
|
|
if (sender().is_null()) {
|
|
abort();
|
|
}
|
|
_api_id = _api_id.cat( sender()->id() );
|
|
return(TT_OK);
|
|
}
|
|
|
|
/*
|
|
* Sets this to be a super message (send to parent type)
|
|
*/
|
|
void _Tt_message::
|
|
set_super()
|
|
{
|
|
_flags |= (1<<_TT_MSG_IS_SUPER);
|
|
}
|
|
|
|
_Tt_string & _Tt_message::
|
|
status_string()
|
|
{
|
|
return(_status_string);
|
|
}
|
|
|
|
|
|
Tt_status _Tt_message::
|
|
set_status_string(_Tt_string st)
|
|
{
|
|
_status_string = st;
|
|
SET_GUARD(_full_msg_guards,_status_string.len(),_TT_MSK_STATUS_STRING);
|
|
|
|
return(TT_OK);
|
|
}
|
|
|
|
|
|
//
|
|
// This method will identify this message as a "start" message if flag is
|
|
// 1. Otherwise it clears the flag associated with this. When turning the
|
|
// flag on we set the status field to TT_WRN_START_MESSAGE because the
|
|
// tooltalk client needs to check for this value to know that this is a
|
|
// start message. When turning the flag off we have to set the status to
|
|
// TT_OK but only if it is still TT_WRN_START_MESSAGE (otherwise we end
|
|
// up stomping on a status code set by the client.).
|
|
//
|
|
void _Tt_message::
|
|
set_start_message(int flag)
|
|
{
|
|
if (flag) {
|
|
set_status((int)TT_WRN_START_MESSAGE);
|
|
_flags |= (1<<_TT_MSG_IS_START_MSG);
|
|
} else {
|
|
if (_status == (int)TT_WRN_START_MESSAGE) {
|
|
SET_GUARD(_full_msg_guards,1,_TT_MSK_STATUS);
|
|
_status = TT_OK;
|
|
}
|
|
_flags &= ~(1<<_TT_MSG_IS_START_MSG);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Returns 1 if this is a start message. Version 1 clients didn't
|
|
// implement the _TT_MSG_IS_START_MSG flag so the only way to tell with
|
|
// them is if the _status field is TT_WRN_START_MESSAGE.
|
|
//
|
|
int _Tt_message::
|
|
is_start_message() const
|
|
{
|
|
return(_status == TT_WRN_START_MESSAGE ||
|
|
(_flags&(1<<_TT_MSG_IS_START_MSG)));
|
|
}
|
|
|
|
void _Tt_message::
|
|
set_awaiting_reply(int flag)
|
|
{
|
|
if (flag) {
|
|
_flags |= (1<<_TT_MSG_AWAITING_REPLY);
|
|
} else {
|
|
_flags &= ~(1<<_TT_MSG_AWAITING_REPLY);
|
|
}
|
|
}
|
|
|
|
int _Tt_message::
|
|
is_awaiting_reply() const
|
|
{
|
|
return (_flags&(1<<_TT_MSG_AWAITING_REPLY));
|
|
}
|
|
|
|
|
|
Tt_status _Tt_message::
|
|
set_status(int st)
|
|
{
|
|
// _status is used in the special case of a start message
|
|
if (st == (int)TT_OK && _status == TT_WRN_START_MESSAGE) {
|
|
return(TT_OK);
|
|
}
|
|
_status = st;
|
|
SET_GUARD(_full_msg_guards,1,_TT_MSK_STATUS);
|
|
return(TT_OK);
|
|
}
|
|
|
|
|
|
//
|
|
// Sets the _handler field of a message for the special case of an
|
|
// observer replying to a start message. This special case is
|
|
// distinguished by turning on the _TT_MSG_OBSERVER flag.
|
|
//
|
|
void _Tt_message::
|
|
set_observer_procid(const _Tt_procid_ptr &p)
|
|
{
|
|
_flags |= (1<<_TT_MSG_OBSERVER);
|
|
_handler = p;
|
|
}
|
|
|
|
|
|
//
|
|
// Clears the _TT_MSG_OBSERVER flag and sets the _handler field back to
|
|
// null.
|
|
//
|
|
void _Tt_message::
|
|
clr_observer_procid()
|
|
{
|
|
_flags &= ~(1<<_TT_MSG_OBSERVER);
|
|
_handler = (_Tt_procid *)0;
|
|
}
|
|
|
|
|
|
static void
|
|
_tt_procid_list_print(const _Tt_ostream &os,
|
|
const _Tt_procid_list_ptr &procs, const char *label)
|
|
{
|
|
if ((! procs.is_null()) && (procs->count() > 0)) {
|
|
os << label << ":\n";
|
|
_Tt_string indent = os.indent();
|
|
os.set_indent( indent.cat( "\t" ));
|
|
_Tt_procid_list_cursor procC( procs );
|
|
while (procC.next()) {
|
|
procC->print( os );
|
|
}
|
|
os.set_indent( indent );
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Prints out a message to os.
|
|
//
|
|
void _Tt_message::
|
|
print(const _Tt_ostream &os) const
|
|
{
|
|
_Tt_arg_list_cursor arg_cursor;
|
|
|
|
os << _tt_enumname(state()) << " ";
|
|
os << _tt_enumname(_paradigm) << " ";
|
|
os << _tt_enumname(_message_class) << " ";
|
|
os << "(" << _tt_enumname(reliability()) << " in ";
|
|
os << _tt_enumname(scope()) << "): ";
|
|
os << (int)_status << " == " << (Tt_status)_status << "\n";
|
|
|
|
os << "id:\t\t" << _api_id << "\n";
|
|
os << "op:\t\t" << _op << "\n";
|
|
if (_args->count() > 0) {
|
|
os << "args:\n";
|
|
_Tt_string indent = os.indent();
|
|
os.set_indent( indent.cat( "\t" ));
|
|
_Tt_arg_list_cursor argC( _args );
|
|
while (argC.next()) {
|
|
argC->print( os );
|
|
}
|
|
os.set_indent( indent );
|
|
}
|
|
if (_contexts->count() > 0) {
|
|
os << "contexts:\n";
|
|
_Tt_string indent = os.indent();
|
|
os.set_indent( indent.cat( "\t" ));
|
|
_Tt_msg_context_list_cursor contextC( _contexts );
|
|
while (contextC.next()) {
|
|
contextC->print( os );
|
|
}
|
|
os.set_indent( indent );
|
|
}
|
|
if (_status_string.len() > 0) {
|
|
os << "status_string:\t" << _status_string << "\n";
|
|
}
|
|
if (! _session.is_null()) {
|
|
os << "session:\t" << _session->address_string() << "\n";
|
|
}
|
|
if (_file.len() > 0) {
|
|
os << "file:\t\t" << _tt_network_path_to_local_path(_file)
|
|
<< "\n";
|
|
}
|
|
if (_object.len() > 0) {
|
|
os << "object:\t\t" << _object << "\n";
|
|
}
|
|
if (_otype.len() > 0) {
|
|
os << "otype:\t\t" << _otype << "\n";
|
|
}
|
|
if (! _sender.is_null()) {
|
|
os << "sender:\t\t[" << _uid << "/" << _gid << "] ";
|
|
_sender->print( os );
|
|
}
|
|
if (_sender_ptype.len() > 0) {
|
|
os << "sender_ptype:\t" << _sender_ptype << "\n";
|
|
}
|
|
if (_pattern_id.len() > 0) {
|
|
os << "pattern:\t" << _pattern_id << "\n";
|
|
}
|
|
if (opnum() != -1) {
|
|
os << "opnum:\t\t" << opnum() << "\n";
|
|
}
|
|
if (! _handler.is_null()) {
|
|
os << "handler:\t";
|
|
_handler->print( os );
|
|
}
|
|
if (_handler_ptype.len() > 0) {
|
|
os << "handler_ptype:\t" << _handler_ptype << "\n";
|
|
}
|
|
_tt_procid_list_print( os, _accepters, "accepters" );
|
|
_tt_procid_list_print( os, _rejecters, "rejecters" );
|
|
_tt_procid_list_print( os, _abstainers, "abstainers" );
|
|
}
|