1 //%% (c) Copyright 1993, 1994 Hewlett-Packard Company
2 //%% (c) Copyright 1993, 1994 International Business Machines Corp.
3 //%% (c) Copyright 1993, 1994 Sun Microsystems, Inc.
4 //%% (c) Copyright 1993, 1994 Novell, Inc.
5 //%% $XConsortium: mp_s_mp.C /main/6 1996/05/09 20:30:03 drk $
8 * @(#)mp_s_mp.C 1.42 95/09/18
10 * Copyright 1990,1993 Sun Microsystems, Inc. All rights reserved.
12 #include "mp_s_global.h"
15 #include "mp_s_procid.h"
16 #include "mp_self_procid.h"
17 #include "mp_rpc_implement.h"
18 #include "mp_rpc_server.h"
19 #include "mp_s_session.h"
20 #include "mp/mp_xdr_functions.h"
23 #include "mp/mp_arg.h"
24 #include "mp_s_pattern.h"
25 #include "mp_signature.h"
26 #include "mp_s_message.h"
27 #include "mp_typedb.h"
28 #include "mp/mp_file.h"
29 #include "util/tt_global_env.h"
30 #include "util/tt_base64.h"
31 #include "util/tt_host.h"
32 #include "util/tt_port.h"
34 #include <sys/resource.h>
38 #include <util/tt_gettext.h>
40 #include <sys/types.h>
44 // global pointer to the _Tt_s_mp object. There should only be one
45 // instance of this object.
46 _Tt_s_mp *_tt_s_mp = (_Tt_s_mp *)0;
51 _flags |= (1<<_TT_MP_IN_SERVER);
52 initial_session = initial_s_session = new _Tt_s_session;
54 _active_fds = new _Tt_int_rec_list();
55 _active_fds_procids = new _Tt_string_list();
56 _mp_start_time = (int)time(0);
62 max_active_messages = 2000;
65 ptable = new _Tt_ptype_table(_tt_ptype_ptid, 50);
66 otable = new _Tt_otype_table(_tt_otype_otid, 50);
67 sigs = new _Tt_sigs_by_op_table(_tt_sigs_by_op_op, 250);
68 opful_pats = new _Tt_patlist_table(_tt_patlist_op, 250);
69 opless_pats = new _Tt_pattern_list();
70 active_procs = new _Tt_s_procid_table(_tt_procid_id, 250);
72 when_last_observer_registered = 1;
73 update_args.message = new _Tt_s_message();
74 _self = (_Tt_s_procid *)new _Tt_self_procid();
82 // Emulate a tt_close() for _self.
83 // XXX Commented out because currently s_remove_procid() neither:
84 // - deletes this session from the interest list, nor
85 // - sends an on_exit message (since _self submits none)
87 // if (! _self.is_null()) {
88 // s_remove_procid( _self );
93 // Initializes a _Tt_s_mp object. This entails initializing
94 // the initial session which is the default session that other clients
95 // connect to. This method will also initialize the global _Tt_s_mp
96 // object if the session is initialized. This is important since the
97 // _Tt_s_mp::init method assumes that the session has been initialized.
98 // XXX: the existence of the s_init and init methods is left over from
99 // an earlier incomplete split of _Tt_mp into server and client subclasses.
100 // Really, there should be just one virtual init method.
109 // initialize "initial" session which is the server session in
110 // server mode and the "default" session in client mode.
112 status = initial_s_session->s_init();
113 if (status == TT_OK) {
125 // Initializes the _Tt_s_mp object. This entails putting the two special
126 // "pseudo-procids" into the _active_fds and _active_fds_procids lists
127 // (see comment for _Tt_s_mp::find_proc)
133 // put in fd for X connection
134 _active_fds->push(new _Tt_int_rec(xfd));
135 _active_fds_procids->push(_Tt_string("X"));
137 #ifdef OPT_UNIX_SOCKET_RPC
138 /* XXX: UNIX_SOCKET */
140 // put in fd for local rpc connections
141 _active_fds->push(new _Tt_int_rec(unix_fd));
142 _active_fds_procids->push(_Tt_string("U"));
144 /* XXX: UNIX_SOCKET */
145 #endif // OPT_UNIX_SOCKET_RPC
151 // Initialize our _Tt_self_procid and register patterns for the
152 // messages we are interested in.
155 _Tt_s_mp::init_self()
157 // Grab the global mutex to lock out other threads
159 _tt_global->grab_mutex();
161 // Increment the counter for the number of RPC calls
162 // handled during the life of this process. This has
163 // to be done here since init_self() ultimately calls
164 // something which calls updateFileSystemEntries(),
165 // yet it's not done through an API or RPC call. Thus,
166 // this line here is somewhat of a bandaid. XXX
167 _tt_global->event_counter++;
169 // Use the lame do-loop hack to avoid repeating the drop_mutex
170 // code after every possible failure...
172 Tt_status status = TT_OK;;
176 // tt_open(), tt_fd()
178 Tt_status status = _self->init();
179 if (status != TT_OK) {
182 status = add_procid( _self );
183 if (status != TT_OK) {
187 status = _handle_Session_Trace();
188 if (status != TT_OK) {
191 status = _observe_Saved();
192 if (status != TT_OK) {
197 _tt_global->drop_mutex();
203 _Tt_s_mp::_handle_Session_Trace()
206 // tt_pattern_create(), tt_pattern_category_set(),
207 // tt_pattern_scope_add(), tt_pattern_session_add(),
208 // tt_pattern_op_add(), tt_pattern_arg_add()
210 _Tt_s_pattern_ptr pat = _Tt_self_procid::s_pattern_create();
211 Tt_status status = pat->set_category( TT_HANDLE );
212 if (status != TT_OK) {
215 status = pat->add_message_class( TT_REQUEST );
216 if (status != TT_OK) {
219 status = pat->add_scope( TT_SESSION );
220 if (status != TT_OK) {
223 status = pat->add_session( _tt_s_mp->initial_s_session->address_string() );
224 if (status != TT_OK) {
227 status = pat->add_op( "Session_Trace" );
228 if (status != TT_OK) {
231 _Tt_arg_ptr arg = new _Tt_arg( TT_IN, "string" );
232 status = pat->add_arg( arg );
233 if (status != TT_OK) {
236 pat->server_callback = _Tt_self_procid::handle_Session_Trace;
238 // tt_pattern_register()
240 status = _self->add_pattern( pat );
241 if (status != TT_OK) {
247 // _Tt_s_procid_ptr s_proc = (_Tt_s_procid *)_self.c_pointer();
248 // status = _tt_s_mp->initial_s_session->s_join( s_proc );
249 // if (status != TT_OK) {
256 _Tt_s_mp::_observe_Saved()
259 // tt_pattern_create(), tt_pattern_category_set(),
260 // tt_pattern_scope_add(), tt_pattern_op_add(), tt_pattern_arg_add()
262 _Tt_s_pattern_ptr pat = _Tt_self_procid::s_pattern_create();
263 Tt_status status = pat->set_category( TT_OBSERVE );
264 if (status != TT_OK) {
267 status = pat->add_message_class( TT_NOTICE );
268 if (status != TT_OK) {
271 status = pat->add_scope( TT_BOTH );
272 if (status != TT_OK) {
275 status = pat->add_session( _tt_s_mp->initial_s_session->address_string() );
276 if (status != TT_OK) {
279 _Tt_string_list_ptr ttpath = _Tt_typedb::tt_path();
280 if (ttpath.is_null()) {
283 _Tt_string_list_cursor pathC( ttpath );
284 while (pathC.next()) {
285 status = pat->add_netfile( *pathC, 1 );
286 if (status != TT_OK) {
290 status = pat->add_op( "Saved" );
291 if (status != TT_OK) {
294 _Tt_arg_ptr arg = new _Tt_arg( TT_IN, "File" );
295 status = pat->add_arg( arg );
296 if (status != TT_OK) {
299 pat->server_callback = _Tt_self_procid::observe_Saved;
301 // tt_pattern_register()
303 status = _self->add_pattern( pat );
304 if (status != TT_OK) {
307 status = pat->join_files(_tt_s_mp->initial_s_session->process_tree_id());
308 if (status != TT_OK) {
316 // Installs a list of signatures. Each signature is installed in a table
317 // called sigs_table that maps op names to lists of signatures with that
318 // same opname. This cuts down on the number of signatures that need to
319 // be examined to dispatch a message.
322 install_signatures(_Tt_signature_list_ptr &s)
324 _Tt_signature_list_cursor sigC(s);
325 _Tt_sigs_by_op_ptr sigs_byop;
327 while (sigC.next()) {
328 sigs_byop = (_Tt_sigs_by_op *)0;
329 if (! sigs->lookup(sigC->op(),sigs_byop)) {
330 sigs_byop = new _Tt_sigs_by_op(sigC->op());
331 sigs_byop->sigs = new _Tt_signature_list();
332 sigs->insert(sigs_byop);
334 sigs_byop->sigs->push(*sigC);
339 remove_signatures(const _Tt_ptype &ptype)
341 _Tt_sigs_by_op_table_cursor sigs_byopC(sigs);
343 while (sigs_byopC.next()) {
344 _Tt_signature_list_cursor sigC(sigs_byopC->sigs);
345 while (sigC.next()) {
346 if (sigC->ptid() == ptype.ptid()) {
354 remove_signatures(const _Tt_otype &otype)
356 _Tt_sigs_by_op_table_cursor sigs_byopC(sigs);
358 while (sigs_byopC.next()) {
359 _Tt_signature_list_cursor sigC(sigs_byopC->sigs);
360 while (sigC.next()) {
361 if (sigC->otid() == otype.otid()) {
369 // Iterates through the given table of ptypes and installs all the
370 // signatures contained in each ptype.
373 install_ptable(_Tt_ptype_table_ptr &p)
375 _Tt_ptype_table_cursor ptypes;
378 ptypes.reset(ptable);
379 while (ptypes.next()) {
380 remove_signatures(**ptypes);
381 install_signatures(ptypes->hsigs());
382 install_signatures(ptypes->osigs());
388 // Iterates through the given table of otypes and installs all the
389 // signatures contained in each otype.
392 install_otable(_Tt_otype_table_ptr &o)
394 _Tt_otype_table_cursor otypes;
397 otypes.reset(otable);
398 while (otypes.next()) {
399 remove_signatures(**otypes);
400 install_signatures(otypes->hsigs());
401 install_signatures(otypes->osigs());
407 // It is important that the mp contain exactly one object for each
408 // procid that is registered because there is state that is contained
409 // in this instance of a procid that shouldn't be duplicated. This
410 // method takes a generic \(neither server nor client\) procid and
412 // the _Tt_s_procid object that the mp has for the given id or else creates
413 // a new object if create_ifnot is equal to 1. When a procid is
414 // initialized, it's signalling fd is added to two parallel lists,
415 // _active_fds and _active_fds_procids. _active_fds contains a list
416 // of fds whereas _active_fds_procids contains a list of procid ids.
417 // Each position in the two lists corresponds to each other. This is
418 // equivalent to having a single list of records where each record
419 // contains an fd and a procid id. These lists are used by the
420 // _Tt_s_mp::main_loop to poll all the fds in the list and match them
421 // with their respective procids.
423 // The _active_fds_procids list can contain two "pseudo-procids" that
424 // are used to keep track of some special fds. These can be "U" for
425 // the special unix socket fd (used if OPT_UNIX_SOCKET_RPC is defined)
426 // that clients use to establish a unix socket rpc connection, and "X"
427 // for the fd that represents the connection to our desktop session.
428 // See _Tt_s_mp::main_loop to see how they are used.
430 // XXX: Replacing the parallel list structure with a list of records
431 // would increase readability.
435 const _Tt_procid_ptr &procid,
436 _Tt_s_procid_ptr &proc_returned,
442 if (! procid.is_null()) {
443 if (! _last_proc_hit.is_null()) {
444 if (_last_proc_hit->is_equal(procid)) {
445 proc_returned = _last_proc_hit;
449 active_procs->lookup(procid->id(),sp);
457 sp = new _Tt_s_procid(procid);
459 /* procid not found, add it to list */
460 if (sp->init() == TT_OK) {
474 // Called in order to generate a unique key for a new procid. This key is
475 // prepended to a procid's session in order to form an id that is unique
476 // among all procids joined to the server's session.
478 _Tt_string _Tt_s_mp::
481 int key = _next_procid_key++;
482 _Tt_string result(_tt_base64_encode((unsigned long)key));
484 result = result.cat(".").cat(_tt_base64_encode((unsigned long)_mp_start_time));
490 // This is the main loop of the message server. This method is
491 // responsible for servicing events such as rpc requests, disconnect
492 // signals from procids, connection requests for unix socket rpc
493 // requests, and events generated from our desktop connection (if
494 // applicable). The main loop checks for the values of exit_main_loop
495 // and of fin and fout (see comments in bin/ttsession/mp_server.C)
496 // before invoking the _Tt_rpc_server::run method which will block on
497 // rpc requests and polling on the supplied list of file descriptors
498 // supplied in the _active_fds list.
503 _Tt_int_rec_list_cursor fds;
504 _Tt_string_list_cursor fd_procid;
507 while (! exit_main_loop && (fin == fout)) {
508 switch (initial_s_session->_rpc_server->run_until(&exit_main_loop,
514 case _TT_RPCSRV_TMOUT:
516 case _TT_RPCSRV_FDERR:
517 // this error code is returned if any of the
518 // file descriptors in _active_fds has input
519 // pending. In the case of file descriptors
520 // associated with procid signalling channels
521 // this means that the connection to them was
522 // lost, in the case of the file descriptor
523 // being associated with the desktop
524 // connection this means that there was an
525 // event generated by the desktop server.
526 // Otherwise, if the file descriptor was the
527 // one associated with the unix socket rpc
528 // socket then this is a new connection
531 // Note that the _Tt_rpc_server::run method
532 // will indicate which fd was active by
533 // negating its value thus the test for being
534 // less than zero indicates that was the fd we
537 fds.reset(_active_fds);
538 fd_procid.reset(_active_fds_procids);
539 while (fds.next() && fd_procid.next()) {
541 if (*fd_procid == "X") {
544 if (initial_session->desktop_event_callback()==-1) {
549 #ifdef OPT_UNIX_SOCKET_RPC
550 } else if ((0 - fds->val)==unix_fd) {
551 // connection request
552 // for local rpc transport.
555 initial_s_session->u_rpc_init();
556 #endif // OPT_UNIX_SOCKET_RPC
558 // signalling channel
562 // connection was lost
564 // signalling channel
567 if (active_procs->lookup(*fd_procid,sp)) {
568 // Before cleaning up,
571 sp->send_on_exit_messages();
573 active_procs->remove(sp->id());
589 // Returns 1 if there exist file-scope patterns for the given pathname.
590 // Uses the two parallel lists _file_scope_paths and
591 // _file_scope_refcounts which form a logical list of records of file
592 // pathnames to number of patterns registered.
594 // XXX: Use of parallel lists is confusing. Recoding using a single list
595 // of records would improve readability.
598 in_file_scope(const _Tt_string &f)
600 if (_file_scope_refcounts.is_null()) {
603 _Tt_int_rec_list_cursor refcounts(_file_scope_refcounts);
604 _Tt_string_list_cursor paths(_file_scope_paths);
606 while (refcounts.next() && paths.next()) {
617 // Adds (subtracts) number of file-scope patterns registered for the
618 // given pathname if add_scope is 1 (0). If the refcount of patterns goes
619 // to 0 then the pathname is removed from the _file_scope_refcounts and
620 // _file_scope_paths lists. See comment for _Tt_s_mp::in_file_scope for
621 // an explanation of these lists.
624 mod_file_scope(const _Tt_string &f, int add_scope)
626 if (_file_scope_refcounts.is_null()) {
627 _file_scope_refcounts = new _Tt_int_rec_list();
628 _file_scope_paths = new _Tt_string_list();
631 _Tt_int_rec_list_cursor refcounts(_file_scope_refcounts);
632 _Tt_string_list_cursor paths(_file_scope_paths);
634 while (refcounts.next() && paths.next()) {
636 refcounts->val += (add_scope ? 1 : -1);
637 if (refcounts->val == 0) {
645 _file_scope_refcounts->push(new _Tt_int_rec(1));
646 _file_scope_paths->push(f);
652 _Tt_s_mp::add_procid(
653 _Tt_s_procid_ptr &proc
656 _active_fds->push(new _Tt_int_rec(-1));
657 _active_fds_procids->push(proc->id());
658 active_procs->insert(proc);
659 _last_proc_hit = proc;
665 // Called in response to a client invoking the tt_close api call. This
666 // method will deallocate any resources that this procid holds and will
667 // remove the procid reference from any global data-structures.
670 s_remove_procid(_Tt_s_procid &proc)
672 proc.cancel_on_exit_messages();
673 // de-activate this procid
675 // remove from list of active procs
676 active_procs->remove(proc.id());