Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / lib / tt / slib / mp_s_mp.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 //%%  (c) Copyright 1993, 1994 Hewlett-Packard Company                  
24 //%%  (c) Copyright 1993, 1994 International Business Machines Corp.    
25 //%%  (c) Copyright 1993, 1994 Sun Microsystems, Inc.                   
26 //%%  (c) Copyright 1993, 1994 Novell, Inc.                             
27 //%%  $XConsortium: mp_s_mp.C /main/6 1996/05/09 20:30:03 drk $                                                         
28 /*
29  *
30  * @(#)mp_s_mp.C        1.42    95/09/18
31  *
32  * Copyright 1990,1993 Sun Microsystems, Inc.  All rights reserved.
33  */
34 #include "mp_s_global.h"
35 #include "mp_s_mp.h"
36 #include "mp/mp_mp.h"
37 #include "mp_s_procid.h"
38 #include "mp_self_procid.h"
39 #include "mp_rpc_implement.h"
40 #include "mp_rpc_server.h"
41 #include "mp_s_session.h"
42 #include "mp/mp_xdr_functions.h"
43 #include "mp_ptype.h"
44 #include "mp_otype.h"
45 #include "mp/mp_arg.h"
46 #include "mp_s_pattern.h"
47 #include "mp_signature.h"
48 #include "mp_s_message.h"
49 #include "mp_typedb.h"
50 #include "mp/mp_file.h"
51 #include "util/tt_global_env.h"
52 #include "util/tt_base64.h"
53 #include "util/tt_host.h"
54 #include "util/tt_port.h"
55 #include <errno.h>
56 #include <sys/resource.h>
57 #include <time.h>
58 #include <unistd.h>
59 #include <nl_types.h>
60 #include <util/tt_gettext.h>
61 #include <tt_const.h>
62 #include <sys/types.h>
63 #include <sys/stat.h>
64 #include <fcntl.h>
65
66 // global pointer to the _Tt_s_mp object. There should only be one
67 // instance of this object.
68 _Tt_s_mp *_tt_s_mp = (_Tt_s_mp *)0;
69
70 _Tt_s_mp::
71 _Tt_s_mp() : _Tt_mp()
72 {
73         _flags |= (1<<_TT_MP_IN_SERVER);
74         initial_session = initial_s_session = new _Tt_s_session;
75         
76         _active_fds = new _Tt_int_rec_list();
77         _active_fds_procids = new _Tt_string_list();
78         _mp_start_time = (int)time(0);
79
80         _min_timeout = -1;
81         _next_procid_key = 0;
82         xfd = -1;
83         exit_main_loop = 0;
84         max_active_messages = 2000;
85         fin = 0;
86         fout = 0;
87         ptable = new _Tt_ptype_table(_tt_ptype_ptid, 50);
88         otable = new _Tt_otype_table(_tt_otype_otid, 50);
89         sigs = new _Tt_sigs_by_op_table(_tt_sigs_by_op_op, 250);
90         opful_pats = new _Tt_patlist_table(_tt_patlist_op, 250);
91         opless_pats = new _Tt_pattern_list();
92         active_procs = new _Tt_s_procid_table(_tt_procid_id, 250);
93         now = 1;
94         when_last_observer_registered = 1;
95         update_args.message = new _Tt_s_message();
96         _self = (_Tt_s_procid *)new _Tt_self_procid();
97 }
98
99
100 _Tt_s_mp::
101 ~_Tt_s_mp()
102 {
103         //
104         // Emulate a tt_close() for _self.
105         // XXX Commented out because currently s_remove_procid() neither:
106         // - deletes this session from the interest list, nor
107         // - sends an on_exit message (since _self submits none)
108         //
109         // if (! _self.is_null()) {
110         //      s_remove_procid( _self );
111         // }
112 }
113
114 // 
115 // Initializes a _Tt_s_mp object. This entails initializing
116 // the initial session which is the default session that other clients
117 // connect to. This method will also initialize the global _Tt_s_mp
118 // object if the session is initialized. This is important since the
119 // _Tt_s_mp::init method assumes that the session has been initialized.
120 // XXX: the existence of the s_init and init methods is left over from
121 // an earlier incomplete split of _Tt_mp into server and client subclasses.
122 // Really, there should be just one virtual init method.
123 // 
124 Tt_status _Tt_s_mp::
125 s_init()
126 {
127         Tt_status               status;
128
129         active_messages = 0;
130
131         // initialize "initial" session which is the server session in
132         // server mode and the "default" session in client mode.
133         
134         status = initial_s_session->s_init();
135         if (status == TT_OK) {
136                 status = init();
137         }
138
139         return(status);
140 }
141
142
143
144
145
146 // 
147 // Initializes the _Tt_s_mp object. This entails putting the two special
148 // "pseudo-procids" into the _active_fds and _active_fds_procids lists
149 // (see comment for _Tt_s_mp::find_proc)
150 // 
151 Tt_status _Tt_s_mp::
152 init()
153 {
154         if (xfd != -1) {
155                 // put in fd for X connection
156                 _active_fds->push(new _Tt_int_rec(xfd));
157                 _active_fds_procids->push(_Tt_string("X"));
158         }
159 #ifdef OPT_UNIX_SOCKET_RPC
160         /* XXX: UNIX_SOCKET */          
161         if (unix_fd != -1) {
162                 // put in fd for local rpc connections
163                 _active_fds->push(new _Tt_int_rec(unix_fd));
164                 _active_fds_procids->push(_Tt_string("U"));
165         }               
166         /* XXX: UNIX_SOCKET */          
167 #endif  // OPT_UNIX_SOCKET_RPC
168
169         return(TT_OK);
170 }
171
172 //
173 // Initialize our _Tt_self_procid and register patterns for the
174 // messages we are interested in.
175 //
176 Tt_status
177 _Tt_s_mp::init_self()
178 {
179         // Grab the global mutex to lock out other threads
180
181         _tt_global->grab_mutex();
182
183         // Increment the counter for the number of RPC calls
184         // handled during the life of this process.  This has
185         // to be done here since init_self() ultimately calls
186         // something which calls updateFileSystemEntries(),
187         // yet it's not done through an API or RPC call.  Thus,
188         // this line here is somewhat of a bandaid. XXX
189         _tt_global->event_counter++;
190
191         // Use the lame do-loop hack to avoid repeating the drop_mutex
192         // code after every possible failure...
193         
194         Tt_status status = TT_OK;;
195
196         do {
197                 //
198                 // tt_open(), tt_fd()
199                 //
200                 Tt_status status = _self->init();
201                 if (status != TT_OK) {
202                         break;
203                 }
204                 status = add_procid( _self );
205                 if (status != TT_OK) {
206                         break;
207                 }
208                 _self->set_fd();
209                 status = _handle_Session_Trace();
210                 if (status != TT_OK) {
211                         break;
212                 }
213                 status = _observe_Saved();
214                 if (status != TT_OK) {
215                         break;
216                 }
217         } while (0);
218
219         _tt_global->drop_mutex();
220
221         return TT_OK;
222 }
223
224 Tt_status
225 _Tt_s_mp::_handle_Session_Trace()
226 {
227         //
228         // tt_pattern_create(), tt_pattern_category_set(),
229         // tt_pattern_scope_add(), tt_pattern_session_add(),
230         // tt_pattern_op_add(), tt_pattern_arg_add()
231         //
232         _Tt_s_pattern_ptr pat = _Tt_self_procid::s_pattern_create();
233         Tt_status status = pat->set_category( TT_HANDLE );
234         if (status != TT_OK) {
235                 return status;
236         }
237         status = pat->add_message_class( TT_REQUEST );
238         if (status != TT_OK) {
239                 return status;
240         }
241         status = pat->add_scope( TT_SESSION );
242         if (status != TT_OK) {
243                 return status;
244         }
245         status = pat->add_session( _tt_s_mp->initial_s_session->address_string() );
246         if (status != TT_OK) {
247                 return status;
248         }
249         status = pat->add_op( "Session_Trace" );
250         if (status != TT_OK) {
251                 return status;
252         }
253         _Tt_arg_ptr arg = new _Tt_arg( TT_IN, "string" );
254         status = pat->add_arg( arg );
255         if (status != TT_OK) {
256                 return status;
257         }
258         pat->server_callback = _Tt_self_procid::handle_Session_Trace;
259         //
260         // tt_pattern_register()
261         //
262         status = _self->add_pattern( pat );
263         if (status != TT_OK) {
264                 return status;
265         }
266         //
267         // tt_session_join()
268         //
269         // _Tt_s_procid_ptr s_proc = (_Tt_s_procid *)_self.c_pointer();
270         // status = _tt_s_mp->initial_s_session->s_join( s_proc );
271         // if (status != TT_OK) {
272         //      return status;
273         // }
274         return TT_OK;
275 }
276
277 Tt_status
278 _Tt_s_mp::_observe_Saved()
279 {
280         //
281         // tt_pattern_create(), tt_pattern_category_set(),
282         // tt_pattern_scope_add(), tt_pattern_op_add(), tt_pattern_arg_add()
283         //
284         _Tt_s_pattern_ptr pat = _Tt_self_procid::s_pattern_create();
285         Tt_status status = pat->set_category( TT_OBSERVE );
286         if (status != TT_OK) {
287                 return status;
288         }
289         status = pat->add_message_class( TT_NOTICE );
290         if (status != TT_OK) {
291                 return status;
292         }
293         status = pat->add_scope( TT_BOTH );
294         if (status != TT_OK) {
295                 return status;
296         }
297         status = pat->add_session( _tt_s_mp->initial_s_session->address_string() );
298         if (status != TT_OK) {
299                 return status;
300         }
301         _Tt_string_list_ptr ttpath = _Tt_typedb::tt_path();
302         if (ttpath.is_null()) {
303                 return TT_ERR_NOMEM;
304         }
305         _Tt_string_list_cursor pathC( ttpath );
306         while (pathC.next()) {
307                 status = pat->add_netfile( *pathC, 1 );
308                 if (status != TT_OK) {
309                         return status;
310                 }
311         }
312         status = pat->add_op( "Saved" );
313         if (status != TT_OK) {
314                 return status;
315         }
316         _Tt_arg_ptr arg = new _Tt_arg( TT_IN, "File" );
317         status = pat->add_arg( arg );
318         if (status != TT_OK) {
319                 return status;
320         }
321         pat->server_callback = _Tt_self_procid::observe_Saved;
322         //
323         // tt_pattern_register()
324         //
325         status = _self->add_pattern( pat );
326         if (status != TT_OK) {
327                 return status;
328         }
329         status = pat->join_files(_tt_s_mp->initial_s_session->process_tree_id());
330         if (status != TT_OK) {
331                 return status;
332         }
333         return TT_OK;
334 }
335
336
337 // 
338 // Installs a list of signatures. Each signature is installed in a table
339 // called sigs_table that maps op names to lists of signatures with that
340 // same opname. This cuts down on the number of signatures that need to
341 // be examined to dispatch a message.
342 // 
343 void _Tt_s_mp::
344 install_signatures(_Tt_signature_list_ptr &s)
345 {
346         _Tt_signature_list_cursor       sigC(s);
347         _Tt_sigs_by_op_ptr              sigs_byop;
348         
349         while (sigC.next()) {
350                 sigs_byop = (_Tt_sigs_by_op *)0;
351                 if (! sigs->lookup(sigC->op(),sigs_byop)) {
352                         sigs_byop = new _Tt_sigs_by_op(sigC->op());
353                         sigs_byop->sigs = new _Tt_signature_list();
354                         sigs->insert(sigs_byop);
355                 } 
356                 sigs_byop->sigs->push(*sigC);
357         }
358 }
359
360 void _Tt_s_mp::
361 remove_signatures(const _Tt_ptype &ptype)
362 {
363         _Tt_sigs_by_op_table_cursor     sigs_byopC(sigs);
364         
365         while (sigs_byopC.next()) {
366                 _Tt_signature_list_cursor sigC(sigs_byopC->sigs);
367                 while (sigC.next()) {
368                         if (sigC->ptid() == ptype.ptid()) {
369                                 sigC.remove();
370                         }
371                 }
372         }
373 }
374
375 void _Tt_s_mp::
376 remove_signatures(const _Tt_otype &otype)
377 {
378         _Tt_sigs_by_op_table_cursor     sigs_byopC(sigs);
379         
380         while (sigs_byopC.next()) {
381                 _Tt_signature_list_cursor sigC(sigs_byopC->sigs);
382                 while (sigC.next()) {
383                         if (sigC->otid() == otype.otid()) {
384                                 sigC.remove();
385                         }
386                 }
387         }
388 }
389
390 // 
391 // Iterates through the given table of ptypes and installs all the
392 // signatures contained in each ptype.
393 // 
394 void _Tt_s_mp::
395 install_ptable(_Tt_ptype_table_ptr &p)
396 {
397         _Tt_ptype_table_cursor  ptypes;
398         
399         ptable = p;
400         ptypes.reset(ptable);
401         while (ptypes.next()) {
402                 remove_signatures(**ptypes);
403                 install_signatures(ptypes->hsigs());
404                 install_signatures(ptypes->osigs());
405         }
406 }
407
408
409 // 
410 // Iterates through the given table of otypes and installs all the
411 // signatures contained in each otype.
412 // 
413 void _Tt_s_mp::
414 install_otable(_Tt_otype_table_ptr &o)
415 {
416         _Tt_otype_table_cursor  otypes;
417         
418         otable = o;
419         otypes.reset(otable);
420         while (otypes.next()) {
421                 remove_signatures(**otypes);
422                 install_signatures(otypes->hsigs());
423                 install_signatures(otypes->osigs());
424         }
425 }
426
427
428 // 
429 // It is important that the mp contain exactly one object for each
430 // procid that is registered because there is state that is contained
431 // in this instance of a procid that shouldn't be duplicated. This
432 // method takes a generic \(neither server nor client\) procid and
433 // returns either
434 // the _Tt_s_procid object that the mp has for the given id or else creates
435 // a new object if create_ifnot is equal to 1. When a procid is
436 // initialized, it's signalling fd is added to two parallel lists,
437 // _active_fds and _active_fds_procids.  _active_fds contains a list
438 // of fds whereas _active_fds_procids contains a list of procid ids.
439 // Each position in the two lists corresponds to each other. This is
440 // equivalent to having a single list of records where each record
441 // contains an fd and a procid id. These lists are used by the
442 // _Tt_s_mp::main_loop to poll all the fds in the list and match them
443 // with their respective procids. 
444 //
445 // The _active_fds_procids list can contain two "pseudo-procids" that
446 // are used to keep track of some special fds. These can be "U" for
447 // the special unix socket fd (used if OPT_UNIX_SOCKET_RPC is defined)
448 // that clients use to establish a unix socket rpc connection, and "X"
449 // for the fd that represents the connection to our desktop session. 
450 // See _Tt_s_mp::main_loop to see how they are used.
451 // 
452 //  XXX: Replacing the parallel list structure with a list of records
453 //  would increase readability.
454 // 
455 int
456 _Tt_s_mp::find_proc(
457                     const _Tt_procid_ptr   &procid,
458                     _Tt_s_procid_ptr &proc_returned,
459                     int               create_ifnot
460                     )
461 {
462         _Tt_s_procid_ptr        sp;
463         
464         if (! procid.is_null()) {
465                 if (! _last_proc_hit.is_null()) {
466                         if (_last_proc_hit->is_equal(procid)) {
467                                 proc_returned = _last_proc_hit;
468                                 return(1);
469                         }
470                 }
471                 active_procs->lookup(procid->id(),sp);
472         }
473         if (!sp.is_null()) {
474                 _last_proc_hit = sp;
475                 proc_returned = sp;
476                 return(1);
477         }
478         if (create_ifnot) {
479                 sp = new _Tt_s_procid(procid);
480                 
481                 /* procid not found, add it to list */
482                 if (sp->init() == TT_OK) {
483                         proc_returned = sp;
484                         add_procid( sp );
485                         return(1);
486                 } else {
487                         return(0);
488                 }
489         } else {
490                 return(0);
491         }
492 }
493
494
495 // 
496 // Called in order to generate a unique key for a new procid. This key is
497 // prepended to a procid's session in order to form an id that is unique
498 // among all procids joined to the server's session.
499 // 
500 _Tt_string _Tt_s_mp::
501 alloc_procid_key()
502 {
503         int             key = _next_procid_key++;
504         _Tt_string      result(_tt_base64_encode((unsigned long)key));
505         
506         result = result.cat(".").cat(_tt_base64_encode((unsigned long)_mp_start_time));
507         return(result);
508 }
509
510
511 // 
512 // This is the main loop of the message server. This method is
513 // responsible for servicing events such as rpc requests, disconnect
514 // signals from procids, connection requests for unix socket rpc
515 // requests, and events generated from our desktop connection (if
516 // applicable).  The main loop checks for the values of exit_main_loop
517 // and of fin and fout (see comments in bin/ttsession/mp_server.C)
518 // before invoking the _Tt_rpc_server::run method which will block on
519 // rpc requests and polling on the supplied list of file descriptors
520 // supplied in the _active_fds list.
521 // 
522 void _Tt_s_mp::
523 main_loop()
524 {
525         _Tt_int_rec_list_cursor         fds;
526         _Tt_string_list_cursor          fd_procid;
527         _Tt_s_procid_ptr                sp;
528
529         while (! exit_main_loop && (fin == fout)) {
530                 switch (initial_s_session->_rpc_server->run_until(&exit_main_loop,
531                                                                   _min_timeout,
532                                                                   _active_fds)) {
533                     case _TT_RPCSRV_ERR:
534                     case _TT_RPCSRV_OK:
535                         break;
536                       case _TT_RPCSRV_TMOUT:
537                         break;
538                     case _TT_RPCSRV_FDERR:
539                         // this error code is returned if any of the
540                         // file descriptors in _active_fds has input
541                         // pending. In the case of file descriptors
542                         // associated with procid signalling channels
543                         // this means that the connection to them was
544                         // lost, in the case of the file descriptor
545                         // being associated with the desktop
546                         // connection this means that there was an
547                         // event generated by the desktop server.
548                         // Otherwise, if the file descriptor was the
549                         // one associated with the unix socket rpc
550                         // socket then this is a new connection
551                         // request.
552                         //
553                         // Note that the _Tt_rpc_server::run method
554                         // will indicate which fd was active by
555                         // negating its value thus the test for being
556                         // less than zero indicates that was the fd we
557                         // were looking for.
558
559                         fds.reset(_active_fds);
560                         fd_procid.reset(_active_fds_procids);
561                         while (fds.next() && fd_procid.next()) {
562                                 if (fds->val < 0) {
563                                         if (*fd_procid == "X") {
564                                                 // X event came in
565                                                 fds->val *= -1;
566                                                 if (initial_session->desktop_event_callback()==-1) {
567                                                         exit_main_loop = 1;
568                                                         xfd = -2;
569                                                         break;
570                                                 }
571 #ifdef OPT_UNIX_SOCKET_RPC
572                                         } else if ((0 - fds->val)==unix_fd) {
573                                                 // connection request
574                                                 // for local rpc transport.
575
576                                                 fds->val = unix_fd;
577                                                 initial_s_session->u_rpc_init();
578 #endif                          // OPT_UNIX_SOCKET_RPC
579                                         } else {
580                                                 // signalling channel
581                                                 // became active for
582                                                 // some procid. This
583                                                 // means the
584                                                 // connection was lost
585                                                 // since the
586                                                 // signalling channel
587                                                 // is a write-only
588                                                 // connection.
589                                                 if (active_procs->lookup(*fd_procid,sp)) {
590                                                         // Before cleaning up,
591                                                         // send any on_exit
592                                                         // messages.
593                                                         sp->send_on_exit_messages();
594                                                         sp->set_active(-1);
595                                                         active_procs->remove(sp->id());
596                                                 }
597                                                 fds.remove();
598                                                 fd_procid.remove();
599                                         }
600                                 }
601                         }
602                         break;
603                     default:
604                         break;
605                 }
606         }
607 }
608
609
610 // 
611 // Returns 1 if there exist file-scope patterns for the given pathname.
612 // Uses the two parallel lists _file_scope_paths and
613 // _file_scope_refcounts which form a logical list of records of file
614 // pathnames to number of patterns registered.
615 // 
616 //  XXX: Use of parallel lists is confusing. Recoding using a single list
617 //  of records would improve readability.
618 // 
619 int _Tt_s_mp::
620 in_file_scope(const _Tt_string &f)
621 {
622         if (_file_scope_refcounts.is_null()) {
623                 return(0);
624         }
625         _Tt_int_rec_list_cursor         refcounts(_file_scope_refcounts);
626         _Tt_string_list_cursor          paths(_file_scope_paths);
627         
628         while (refcounts.next() && paths.next()) {
629                 if (*paths == f) {
630                         return(1);
631                 }
632         }
633         
634         return(0);
635 }
636
637
638 // 
639 // Adds (subtracts) number of file-scope patterns registered for the
640 // given pathname if add_scope is 1 (0). If the refcount of patterns goes
641 // to 0 then the pathname is removed from the _file_scope_refcounts and
642 // _file_scope_paths lists. See comment for _Tt_s_mp::in_file_scope for
643 // an explanation of these lists.
644 // 
645 void _Tt_s_mp::
646 mod_file_scope(const _Tt_string &f, int add_scope)
647 {
648         if (_file_scope_refcounts.is_null()) {
649                 _file_scope_refcounts = new _Tt_int_rec_list();
650                 _file_scope_paths = new _Tt_string_list();
651         }
652         
653         _Tt_int_rec_list_cursor         refcounts(_file_scope_refcounts);
654         _Tt_string_list_cursor          paths(_file_scope_paths);
655         
656         while (refcounts.next() && paths.next()) {
657                 if (*paths == f) {
658                         refcounts->val += (add_scope ? 1 : -1);
659                         if (refcounts->val == 0) {
660                                 refcounts.remove();
661                                 paths.remove();
662                         }
663                         return;
664                 }
665         }
666         if (add_scope) {
667                 _file_scope_refcounts->push(new _Tt_int_rec(1));
668                 _file_scope_paths->push(f);
669         }
670 }
671
672
673 Tt_status
674 _Tt_s_mp::add_procid(
675                      _Tt_s_procid_ptr &proc
676                      )
677 {
678         _active_fds->push(new _Tt_int_rec(-1));
679         _active_fds_procids->push(proc->id());
680         active_procs->insert(proc);
681         _last_proc_hit = proc;
682         return TT_OK;
683 }
684
685
686 // 
687 // Called in response to a client invoking the tt_close api call. This
688 // method will deallocate any resources that this procid holds and will
689 // remove the procid reference from any global data-structures. 
690 // 
691 Tt_status _Tt_s_mp::
692 s_remove_procid(_Tt_s_procid &proc)
693 {
694         proc.cancel_on_exit_messages();
695         // de-activate this procid
696         proc.set_active(0);
697         // remove from list of active procs
698         active_procs->remove(proc.id());
699         
700         return(TT_OK);
701 }