Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / lib / tt / lib / mp / mp_session.C
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 //%%  $TOG: mp_session.C /main/13 1999/09/16 13:46:46 mgreess $                                                         
6 /*
7  * @(#)mp_session.C     1.84 96/01/10
8  *
9  * Tool Talk Message Passer (MP) - mp_session.cc
10  *
11  * Copyright (c) 1990,1992 by Sun Microsystems, Inc.
12  *
13  * Implementation of the _Tt_session class.
14  */
15 #include "util/tt_global_env.h"
16 #include "util/tt_xdr_version.h"
17 #include "util/tt_host.h"
18 #include "util/tt_port.h"
19 #include "util/tt_gettext.h"
20 #include "mp/mp_global.h"
21 #include "mp/mp_message.h"
22 #include "mp/mp_mp.h"
23 #include "mp/mp_c_global.h"
24 #include "mp/mp_c_session.h"
25 #include "mp/mp_c_mp.h"
26 #include "mp/mp_pattern.h"
27 #include "mp/mp_rpc_client.h"
28 #include "mp/mp_rpc_interface.h"
29 #include "mp/mp_session.h"
30 #include "mp/mp_desktop.h"
31 #include "mp/mp_xdr_functions.h"
32 #include <unistd.h>
33
34 #ifdef OPT_UNIX_SOCKET_RPC
35 #       include <sys/socket.h>
36 #       include <sys/un.h>
37 #endif // OPT_UNIX_SOCKET_RPC
38
39
40 _Tt_session::
41 _Tt_session()
42 {
43         _env = _TT_ENV_LAST;
44         _is_server = 0;         // default server mode
45         _is_dead = 0;
46         _rpc_version = 0;
47 }
48
49
50 _Tt_session::
51 ~_Tt_session()
52 {
53         if (! _desktop.is_null()) {
54                 if (_is_server && _env == _TT_ENV_X11 && (_id.len() > 0)) {
55                         if (   (! _desktop->del_prop(TT_XATOM_NAME))
56                             || (! _desktop->del_prop(TT_CDE_XATOM_NAME)))
57                         {
58                                 _tt_syslog( 0, LOG_WARNING,
59                                             catgets( _ttcatd, 1, 14,
60                                                      "could not delete the X "
61                                                      "root window property %s "
62                                                      "advertising this "
63                                                      "session" ),
64                                             TT_XATOM_NAME );
65                         }
66                 }
67         }
68 #ifdef OPT_UNIX_SOCKET_RPC
69         if (_is_server && _socket_name.len()) {
70                 (void)unlink((char *)_socket_name);
71         }
72 #endif
73 }
74
75
76
77 #ifdef OPT_UNIX_SOCKET_RPC
78 // 
79 // Returns the name of the socket file if the unix socket rpc option is
80 // enabled. Note that the name should be unique for all sessions running
81 // on the same machine so it has to be derived from the session id
82 // (which has the required uniqueness properties).
83 // 
84 char * _Tt_session::
85 local_socket_name()
86 {
87 #define SPRFX "/tmp/.TT"
88
89         if (_socket_name.len() == 0) {
90                 char *sname = (char *)malloc(_id.len() + strlen(SPRFX) + 1); 
91                 char *sc;
92
93                 sprintf(sname,"%s%s", SPRFX, (char *)_id);
94                 sc = sname;
95                 while (*sc) {
96                         if (*sc == ' ') {
97                                 *sc = '_';
98                         }
99                         sc++;
100                 }
101                 _socket_name = sname;
102                 free((MALLOCTYPE *)sname);
103         }
104         
105         return((char *)_socket_name);
106 }
107
108 // 
109 // Opens a connection to the unix socket bound to the given socket name.
110 // If successful returns the fd for the connection. Otherwise, returns
111 // -1. 
112 //
113 int
114 c_open_unix_socket(char *socket_name)
115 {
116         int                     sock;
117         struct sockaddr_un      server_addr;
118         sock = socket(AF_UNIX, SOCK_STREAM, 0);
119         if (sock < 0) {
120                 _tt_syslog( 0, LOG_ERR, "c_open_unix_socket(): socket(): %m" );
121                 return -1;
122         }
123         memset(&server_addr, 0, sizeof(server_addr));
124         server_addr.sun_family = AF_UNIX;
125         strcpy(server_addr.sun_path, socket_name);
126 #if defined(ultrix) || defined(_AIX) || defined(hpux) || defined(__osf__)
127         int servlen = strlen(server_addr.sun_path) + sizeof(server_addr.sun_fam\
128 ily);
129         if (connect(sock, (sockaddr *)&server_addr, servlen) < 0) {
130 #else
131         if (connect(sock, (sockaddr *)&server_addr, sizeof(sockaddr_un)) < 0) {
132 #endif
133                 return(-1);
134         }
135
136         return(sock);
137 }
138
139 #endif // OPT_UNIX_SOCKET_RPC
140
141
142 //
143 // Called if an event comes in from our desktop connection.
144 //
145 int  _Tt_session::
146 desktop_event_callback()
147 {
148         if (! _desktop->process_event()) {
149                 return (-1);
150         }
151         else 
152                 return 0;
153 }
154
155
156 // 
157 // Initializes a session with the assumption that the server session is
158 // already running. If the server session isn't running then this method
159 // will return an error as opposed to attempting to autostart a new
160 // session (see _Tt_session::c_init). This is intended as a lower-level
161 // init function used by c_init or whenever autostarting is not required.
162 //
163 // Returns:
164 //      TT_OK
165 //      TT_ERR_ACCESS   Could not init desktop (diagnostic emitted)
166 //      TT_WRN_NOTFOUND No advertised address
167 //      TT_ERR_INVALID  Could not parse advertised address
168 //      TT_ERR_NO_MATCH Advertised address's version is too new
169 //                      (diagnostic emitted)
170 //      TT_ERR_ADDRESS  Could not find advertised host
171 //      TT_ERR_NOMP     Could not init as rpc client
172 // 
173 Tt_status _Tt_session::
174 client_session_init()
175 {               
176         // this is a client of this session. Note that since this
177         // function may be called in the server, we can't use
178         // _tt_mp->in_server().
179         //
180         Tt_status err;
181         int                     rpc_init_done = 0;
182         _Tt_host_ptr            lh;
183
184
185         _is_server = 0;
186         if (env() == _TT_ENV_X11 && _desktop.is_null()) {
187                 _desktop = new _Tt_desktop();
188                 if (! _desktop->init(_displayname, _TT_DESKTOP_X11)) {
189                         return(TT_ERR_ACCESS);
190                 }
191         }
192         if (_address_string.len() == 0) {
193                 if (find_advertised_address(_address_string) != TT_OK) {
194                         return(TT_WRN_NOTFOUND);
195                 }
196         }
197         if (_address_string.len() == 0) {
198                 // Don't call parsed_address() with an empty string,
199                 // or it will think we're trying to create an address
200                 // string instead of parse it.  parsed_address()
201                 // shouldn't be this cute. XXX
202                 return TT_ERR_INVALID;
203         }
204         if ((err = parsed_address(_address_string)) != TT_OK) {
205                 _address_string = (char *)0;
206                 return(err);
207         }
208         if (_TT_AUTH_ICEAUTH == _auth.auth_level() &&
209             (err = _auth.retrieve_auth_cookie()) != TT_OK) {
210                 return err;
211         }
212         if (! _tt_global->find_host(_hostaddr, _host, 1)) {
213                 return(TT_ERR_ADDRESS);
214         }
215
216         if (_id.len() == 0) {
217                 (void)set_id();
218         }
219
220 #ifdef OPT_UNIX_SOCKET_RPC
221         if (_tt_global->get_local_host(lh)) {
222                 // if we are in the same host as the server session
223                 // then we attempt to connect to its advertised unix
224                 // socket to set up an rpc connection. If we succeed
225                 // then we set rpc_init_done to 1 to prevent a normal
226                 // tcp rpc connection from being made.
227                 if (lh->stringaddr() == _host->stringaddr()) {
228                         _u_sock = c_open_unix_socket(local_socket_name());
229                         if (_u_sock != -1) {
230                                 _rpc_client = new _Tt_rpc_client(_u_sock);
231                                 if (_rpc_client->init(lh, _rpc_program,
232                                                       _rpc_version,
233                                                       _server_uid,
234                                                       &_auth)) {
235                                         rpc_init_done = 1;
236                                         // Since we opened the fd ourselves,
237                                         // clnt_destroy won\'t close it
238                                         // unless we tell it it\'s OK.
239                                         clnt_control(_rpc_client->rpc_handle(),
240                                                      CLSET_FD_CLOSE,
241                                                      (char *) NULL);
242                                 }
243                         }
244                 }
245         }
246 #endif  // OPT_UNIX_SOCKET_RPC
247         if (! rpc_init_done) {
248                 _rpc_client = new _Tt_rpc_client();
249                 if (! _rpc_client->init(_host, _rpc_program, _rpc_version,
250                                         _server_uid, _auth)) {
251                         return(TT_ERR_NOMP);
252                 }
253         }
254
255         // Get and save the file descriptor for this session.
256         _tt_mp->save_session_fd(_rpc_client->socket());
257         return(TT_OK);
258 }
259
260
261 // 
262 // Verifies that the server side of the session is alive and is a
263 // ToolTalk session. Currently this is done by first invoking rpc
264 // procedure 0 to see if the session is responding to rpc requests. If
265 // that succeeds then we invoke rpc procedure TT_RPC_VRFY_SESSION which
266 // is a reasonably large number. The reply to this procedure should be
267 // the session id of the session we're talking to. This is a fairly good
268 // (but not foolproof!) method of verifying that this is a ToolTalk
269 // session.
270 //
271 // In fact it seems to be too picky, if the session id we have is
272 // different only in the IP address, it may just be an alternate
273 // IP address for the very same session.  
274 //
275 // Returns:
276 //      TT_OK
277 //      TT_ERR_NOMP     Session unreachable or a hoaxer
278 //      TT_ERR_NO_MATCH Session has wrong version
279 //      TT_ERR_INVALID  Could not parse advertised address
280 //      TT_ERR_AUTHORIZATION    RPC authorization error
281 //
282 Tt_status _Tt_session::
283 ping()
284 {
285         Tt_status       is_live;
286         _Tt_string      sid;
287         
288         // We used to call the NULLPROC here first, but that seems
289         // to be a waste of a round-trip since it doesn't tell
290         // us anything that the TT_RPC_VRFY_SESSION call doesn't.
291
292         is_live = call((int)TT_RPC_VRFY_SESSION,
293                        (xdrproc_t)xdr_void, 0,
294                        (xdrproc_t)tt_xdr_string,
295                        (char *)&sid);
296
297         // We used to string-compare the returned session id with the one we
298         // have, but that was too picky since the IP address can usefully be
299         // different.  Skip the check for now, perhaps we should check at
300         // least some of the components (UNIX pid?)  We already know the
301         // transient RPC number is good, and most everything else is
302         // constant.  We do make a minimal check that the id string is non
303         // null, this might catch the (unlikely) case where the program at
304         // the other end isn't a ttsession but does happen to have a
305         // procedure with a number the same as TT_RPC_VRFY_SESSION,
306         // although in that case I'd expect the RPC to fail in the
307         // XDR routines.
308
309         if (is_live == TT_OK && 0 == sid.len()) {
310                 is_live = TT_ERR_NOMP;
311         }
312
313
314         if (is_live == TT_ERR_UNIMP) {
315                 is_live = TT_ERR_INTERNAL;
316         }
317
318         // And finally, for reasons I haven't quite figured out,
319         // if the session id we have *isn't* equal to the one returned
320         // by ttsession, file scoped messages fail.  I suspect
321         // pattern matching somewhere compares the ids.
322         // So, if the ttsession thinks its name is different, replace
323         // our idea of the name with its idea of its name.
324
325         if (is_live == TT_OK) {
326                 set_id(sid);
327         }
328
329         return(is_live);
330 }
331
332
333 // 
334 // Invokes an rpc call named by the rpc_proc parameter on the server
335 // session and returns any results. If timeout is anything other than -1
336 // then it will be used as the timeout value. Otherwise a suitable
337 // timeout value is chosen. If rebind is 1 then a new rpc connection will
338 // be attempted if this rpc fails.
339 //
340 // Returns:
341 //      TT_OK
342 //      TT_ERR_NOMP     Could not talk to session
343 //      TT_ERR_VERSION_MISMATCH RPC VERSMISMATCH
344 //      TT_ERR_UNIMP    rpc_proc not implemented by session
345 //      TT_ERR_INVALID  Could not parse address
346 //      TT_ERR_AUTHORIZATION    RPC authorization error
347 //
348 Tt_status _Tt_session::
349 call(int rpc_proc,
350      xdrproc_t xdr_arg_fn, char *arg,
351      xdrproc_t xdr_res_fn, char *res,
352      int timeout, int rebind)
353 {
354         //
355         // Ensure global xdr version is set to proper value for this session.
356         //
357         int xdr_version_2_use = _rpc_version;
358         //
359         // Some rpc calls use an xdr version number that is greater
360         // than the version number of the rpc protocol they exist in.
361         // See e.g. _tt_rpc_add_pattern_with_context().
362         //
363         switch (rpc_proc) {
364             case TT_RPC_ADD_PATTERN_WITH_CONTEXT:
365                 if (xdr_version_2_use < TT_CONTEXTS_XDR_VERSION) {
366                         xdr_version_2_use = TT_CONTEXTS_XDR_VERSION;
367                 }
368                 break;
369         }
370         _Tt_xdr_version ver(xdr_version_2_use);
371         Tt_status               status;
372         clnt_stat               rpc_status;
373         int                     processing;
374         int                     retry;
375         int                     tmout;
376
377         if (_rpc_client.is_null()) {
378                 return(TT_ERR_INTERNAL);
379         }
380
381         if (timeout == -1) {
382                 switch (rpc_proc) {
383                       case TT_RPC_HDISPATCH:
384                       case TT_RPC_HUPDATE_MSG:
385                         rebind = 1;
386                         /* fall through */
387                       case TT_RPC_DISPATCH_2:
388                       case TT_RPC_DISPATCH_2_WITH_CONTEXT:
389                       case TT_RPC_UPDATE_MSG_2:
390                       case TT_RPC_MSGREAD_2:
391                         tmout = -1;
392                         break;
393                       default:
394                         tmout = TT_RPC_TMOUT;
395                         break;
396                 }
397         } else {
398                 tmout = timeout;
399         }
400
401         retry = 5;
402         processing = 1;
403         status = TT_ERR_NOMP;
404         while (processing && retry >= 0) {
405                 if (_is_dead) {
406                         // We sometimes hang if we call a dead session
407                         rpc_status = RPC_CANTRECV;
408                         if (! _rpc_client->init(_host, _rpc_program,
409                                                 _rpc_version,
410                                                 _server_uid,
411                                                 _auth)) {
412                                 status = TT_ERR_NOMP;
413                                 processing = 0;
414                                 break;
415                         }
416
417                 } else {
418                         rpc_status = _rpc_client->call(rpc_proc, xdr_arg_fn,
419                                                        arg, xdr_res_fn, res,
420                                                        tmout);
421                 }
422                 switch (rpc_status) {
423                       case RPC_SUCCESS:
424                         status = TT_OK;
425                         processing = 0;
426                         break;
427                       case RPC_CANTRECV:
428                         _is_dead = 1;
429                         status = TT_ERR_NOMP;
430                         retry--;
431                         break;
432                       case RPC_VERSMISMATCH:
433                       case RPC_PROGVERSMISMATCH:
434                         status = TT_ERR_VERSION_MISMATCH;
435                         processing = 0;
436                         break;
437                       case RPC_TIMEDOUT:
438                         if (tmout == 0 || tmout == -1) {
439                                 // rpc always returns a timeout error if we're
440                                 // in message-passing mode
441                                 status = TT_OK;
442                         } else {
443                                 // network errors
444                                 status = TT_ERR_NOMP;
445                         }
446                         processing = 0;
447                         break;
448                       case RPC_CANTSEND:
449                         if (!rebind) {
450                                 status = TT_ERR_NOMP;
451                                 retry--;
452                                 break;
453                         }
454                         // try to rebind _rpc_client and try again
455                         if (! _rpc_client->init(_host, _rpc_program,
456                                                 _rpc_version,
457                                                 _server_uid,
458                                                 _auth)) {
459                                 status = TT_ERR_NOMP;
460                                 processing = 0;
461                                 break;
462                         }
463                         continue;
464                       case RPC_PROCUNAVAIL:
465                         // We get this if there is a mild version 
466                         // mismatch, e.g. a 1.1 library talking to 
467                         // a 1.0.x server, and one of the new
468                         // API calls is used.  This is relatively
469                         // benign, just let the user know that
470                         // his call is unimplemented in this system
471                         status = TT_ERR_UNIMP;
472                         processing = 0;
473                         break;
474                       case RPC_AUTHERROR:
475                         status = TT_ERR_AUTHORIZATION;
476                         processing = 0;
477                         break;
478                       default:
479                         status = TT_ERR_INTERNAL;
480                         processing = 0;
481                         break;
482                 }
483         }
484
485         if (status == TT_ERR_NOMP &&
486             !_tt_mp->in_server() &&
487             !_tt_c_mp->default_c_session.is_null() &&
488             has_id(_tt_c_mp->default_c_session->address_string())) {
489                 _tt_c_mp->default_c_session = NULL;
490         }
491
492         return(status);
493 }
494
495
496 // 
497 // Attempts to find the address of the server session. This is done
498 // according to what kind of environment or session type we're in. 
499 //
500 Tt_status _Tt_session::
501 find_advertised_address(_Tt_string &session_addr)
502 {
503         switch (env()) {
504               case _TT_ENV_X11:
505                 if ((! _desktop->get_prop(TT_CDE_XATOM_NAME, session_addr)) &&
506                     (! _desktop->get_prop(TT_XATOM_NAME, session_addr))) {
507                         return(TT_ERR_NOMP);
508                 }
509                 return(TT_OK);
510               case _TT_ENV_PROCESS_TREE:
511                 if (_address_string.len() == 0) {
512                         session_addr = _tt_get_first_set_env_var(2, TT_CDE_XATOM_NAME, TT_XATOM_NAME);
513                 } else {
514                         session_addr = _address_string;
515                 }
516                 return(TT_OK);          
517               case _TT_ENV_LAST:
518               default:
519                 return(TT_ERR_NOMP);
520         }
521 }
522
523
524 //
525 // Returns a number indicating what type of session we're in.
526 //
527 _Tt_env _Tt_session::
528 env()
529 {
530         if (_tt_mp->in_server()) {
531                 if (_env == _TT_ENV_LAST && getenv("DISPLAY")) {
532                         _env = _TT_ENV_X11;
533                 }
534                 return(_env);
535         } else if (_env != _TT_ENV_LAST) {
536                 return(_env);
537         } else {
538                 if (_tt_get_first_set_env_var(2, TT_CDE_XATOM_NAME, TT_XATOM_NAME)) {
539                         return(_env = _TT_ENV_PROCESS_TREE);
540                 } else if (getenv("DISPLAY")) {
541                         return(_env = _TT_ENV_X11);
542                 } else {
543                         return(_TT_ENV_LAST);
544                 }
545         }
546 }
547
548
549 // 
550 // Sets the session-type for the session. This affects how the session id
551 // is advertised to potential clients. 
552 // 
553 void _Tt_session::
554 set_env(_Tt_env session_env, _Tt_string arg)
555 {
556         _env = session_env;
557         switch (_env) {
558               case _TT_ENV_X11:
559                 _displayname = arg;
560                 break;
561               default:
562                 break;
563         }
564 }
565
566
567
568 // 
569 // Returns the ToolTalk session id for the X session named by xdisp. Note
570 // that no actual contact is attempted.
571 // 
572 _Tt_string _Tt_session::
573 Xid(_Tt_string xdisp)
574 {
575         return _desktop->session_name(xdisp);
576 }
577
578 /*
579 void _Tt_session::
580 print(FILE *fs) const
581 {
582         fprintf(fs,"_Tt_session::\n");
583 }
584 */
585
586 //
587 // Used to set or get the address string of a session as well as set
588 // appropiately the _rpc_version field of the session. If addr_string is
589 // null, then parsed_address will set the address string of the session.
590 // In this case, it sets _rpc_version to the default TT_RPC_VERSION. If
591 // addr_string is not null then parsed_address will attempt to parse the
592 // string and extract the information in it. In this case, if the
593 // addr_string happens to be an fcs1 version of session addresses then
594 // _rpc_version is set to 1, otherwise it is set to TT_RPC_VERSION.
595 //
596 // Note that the intended convention for address strings is that only the
597 // information that is known to this method will be parsed out of them.
598 // If there is any information beyond that then it is left uninterpreted.
599 // This means that future ToolTalk versions are free to append
600 // information to the end of an address string (as is already done
601 // below) without compromising compatibility with older clients.
602 //
603 // Returns:
604 //      TT_OK
605 //      TT_ERR_INVALID  Could not parse address
606 //      TT_ERR_NO_MATCH Address version is too new (diagnostic emitted)
607 //
608 Tt_status _Tt_session::
609 parsed_address(_Tt_string &addr_string)
610 {
611 #define IPVADDRLEN      16
612         char            session_host[IPVADDRLEN];
613         char            strid[BUFSIZ];
614         int             junk_version = 1;
615         Tt_status       status;
616         const char      *addr_format_fmt = "%%ld %%d %%d %%d %%lu %%%ds %%d";
617         char             addr_format[32];
618         const char      *fcs1_addr_format_fmt = "%%ld %%d %%d %%d %%lu %%%ds";
619         char             fcs1_addr_format[32];
620         
621         //
622         // Note: the fcs 1.0 version of tooltalk uses the first 6
623         // fields in addr_format. Changing these first 6 fields
624         // compromises binary compatibility with the 1.0 version.
625         // Additional fields can be added at the end of addr_format as
626         // long as if the parsing fails then the old format
627         // (fcs1_addr_format) is tried.
628         //
629         _rpc_version = TT_RPC_VERSION;
630         if (addr_string.len() == 0) {
631                 int ipaddr_len;
632
633                 // set address string
634                 if (_host.is_null()) {
635                         return(TT_ERR_INTERNAL);
636                 }
637                 if (_host->stringaddr().len() == 0) {
638                         return(TT_ERR_INTERNAL);
639                 }
640
641                 ipaddr_len = _host->stringaddr().len();
642                 if (ipaddr_len > IPVADDRLEN) ipaddr_len = IPVADDRLEN;
643
644                 sprintf(fcs1_addr_format, fcs1_addr_format_fmt, ipaddr_len);
645                 sprintf(addr_format,      addr_format_fmt,      ipaddr_len);
646
647                 // put version number for format first (this is so we
648                 // can change the format later)
649                 sprintf(strid, "%02d ", _TT_XATOM_VERSION);
650                 sprintf(strid+3, addr_format,
651                         (long)_pid,
652                         _rpc_program,
653                         junk_version,
654                         (int)_auth.auth_level(),
655                         (long)_server_uid,
656                         (char *)_host->stringaddr(),
657                         _rpc_version);
658                 
659                 addr_string = strid;
660                 if ((status = _auth.set_sessionid(
661                                                 _rpc_program,
662                                                 _auth.auth_level(),
663                                                 _host->stringaddr(),
664                                                 _rpc_version)) != TT_OK) {
665                     _tt_syslog(0, LOG_ERR,"_auth.set_sessionid() != TT_OK");
666                     return(status);
667                 }
668         } else {
669                 // get (parse) address string
670                 char *str = (char *)addr_string;
671
672                 sprintf(fcs1_addr_format, fcs1_addr_format_fmt, IPVADDRLEN);
673                 sprintf(addr_format,      addr_format_fmt,      IPVADDRLEN);
674
675                 // check version number of format first
676
677                 // XXX: note that if _TT_XATOM_VERSION is ever changed
678                 // then backward compatibility is seriously
679                 // compromised. 
680
681                 if (atoi(str) != _TT_XATOM_VERSION) {
682                         _tt_syslog( 0, LOG_ERR,
683                                     catgets( _ttcatd, 1, 15,
684                                              "address version is %d, but "
685                                              "I only understand %d! (address: "
686                                              "<%s>)" ),
687                                     atoi(str), _TT_XATOM_VERSION,
688                                     addr_string.operator const char *() );
689                         return TT_ERR_NO_MATCH;
690                 }
691                 
692                 // XXX: Originally, the fcs1_addr_format put in a
693                 // field describing the rpc version of the server.
694                 // However, the fcs1 version of client_session_init
695                 // erroneously initialized the rpc connection with the
696                 // *server* rpc version rather than its own. Thus we
697                 // can't use the rpc version field in fcs1_addr_format
698                 // because then old fcs1.0 clients would mistakenly
699                 // initialize themselves as version 1+ clients. Thus
700                 // (sigh) we have to add a field at the end of
701                 // fcs1_addr_format that is the real rpc version of
702                 // the server. This is the reason that the first rpc
703                 // version parsed from addr_format is thrown away. 
704
705                 long long_pid;
706                 long long_server_uid;
707                 _Tt_auth_level auth_level;
708                 if (7 != sscanf(str+3, addr_format,
709                                 &long_pid,
710                                 &_rpc_program,
711                                 &junk_version, /* always 1 ... */
712                                 &auth_level,
713                                 &long_server_uid,
714                                 session_host,
715                                 &_rpc_version)) {
716
717                         // new format scan failed. Try to parse the
718                         // string for the old format
719
720                         if (6 != sscanf(str+3, fcs1_addr_format,
721                                         &long_pid,
722                                         &_rpc_program,
723                                         &_rpc_version,
724                                         &auth_level,
725                                         &long_server_uid,
726                                         session_host)) {
727                                 _pid = (pid_t) long_pid;
728                                 _server_uid = (uid_t) long_server_uid;
729                                 return(TT_ERR_INVALID);
730                         } else {
731                                 _rpc_version = 1;
732                         }
733                 }
734                 _pid = (pid_t) long_pid;
735                 _server_uid = (uid_t) long_server_uid;
736                 _hostaddr = session_host;
737                 _auth.set_auth_level(auth_level);
738                 if ((status = _auth.set_sessionid(
739                                 _rpc_program,
740                                 auth_level,
741                                 _hostaddr,
742                                 _rpc_version)) != TT_OK) {
743                     _tt_syslog(0, LOG_ERR,"_auth.set_sessionid() != TT_OK");
744                     return(status);
745                 }
746         }
747
748         return(TT_OK);
749 }
750
751
752 // 
753 // Sets the id of a session. Note that addressing information (the rpc
754 // number and version) are not part of the id. This makes it possible in
755 // the future to provide server address rebinding.
756 // 
757 Tt_status _Tt_session::
758 set_id(char *id)
759 {
760         char                    host[64];
761         char                    dpname[125];
762         int                     svnum;
763         char                    *ssid;
764         
765         if (id != (char *)0) {
766                 _id = id;
767                 switch (_id[0]) {
768                       case 'X':
769                         // construct a suitable DISPLAY name from the id
770                         // which should have the format "X <host> <server_num>"
771                         if (sscanf((char *)id, "X %s %d", host, &svnum) != 2) {
772                                 return(TT_ERR_SESSION);
773                         }
774                         sprintf(dpname, "%s:%d", host, svnum);
775                         _displayname = dpname;
776                         _server_num = svnum;
777                         _env = _TT_ENV_X11;
778                         break;
779                       case 'P':
780                         // A process-tree session id is just an address string
781                         // preceded by "P ".
782                         _address_string = _id.mid(2, _id.len());
783                         _env = _TT_ENV_PROCESS_TREE;
784                         break;
785                       default:
786                         return(TT_ERR_SESSION);
787                 }
788                 
789         } else {
790                 // set the "id" which is the publicly visible *logical*
791                 // address of this session.
792                 ssid = _tt_get_first_set_env_var(2, TT_CDE_START_SID, TT_START_SID);
793                 if (ssid != (char *)0) {
794                         _id = ssid;
795                 } else {
796                         switch (env()) {
797                               case _TT_ENV_X11:
798                                 _type = "X";
799                                 if (! _displayname.len()) {
800                                         _displayname = _tt_global->xdisplayname;
801                                 }
802                                 _id = Xid(_displayname);
803                                 break;
804                               case _TT_ENV_PROCESS_TREE:
805                                 _type = "P";
806                                 _server_num = _pid;
807                                 // sami said originally:
808                                 // we need to include the address string in
809                                 // the id of a process-tree session because
810                                 // there is no alternate means of finding
811                                 // the address (ie. for X11 the id could be
812                                 // rid of address info because the X server
813                                 // served as the alternate way of finding
814                                 // the address).
815                                 // rfm sez, 16 June 94:
816                                 // Of course that alternate way was a bad
817                                 // idea since it means other users can't
818                                 // send messages using the session because
819                                 // they can't contact the X server.
820                                 _id = process_tree_id();
821                                 break;
822                               case _TT_ENV_LAST:
823                               default:
824                                 return(TT_ERR_INTERNAL);
825                         }
826                 }
827         }
828         
829         return(TT_OK);
830 }
831
832
833 // 
834 // Returns a process-tree id for this session. This is essentially just
835 // the address of the session preceded by a "P". The purpose of this is
836 // that whenever this exact session needs to be advertised to a
837 // persistent medium (as is done with file-scope messages) this version
838 // of the session id is used so that if the session goes down and comes
839 // up again, the session id stored on disk will become stale.
840 // 
841 _Tt_string _Tt_session::
842 process_tree_id()
843 {
844         _Tt_string      result = "P ";
845
846         return(result.cat(_address_string));
847 }
848
849
850 bool_t _Tt_session::
851 xdr(XDR *xdrs)
852 {
853         return(_id.xdr(xdrs) && _address_string.xdr(xdrs));
854 }
855
856
857 _Tt_string _Tt_session::
858 address_string()
859 {
860         return(_address_string);
861 }
862
863 _Tt_string _Tt_session::
864 displayname()
865 {
866         return(_displayname);
867 }
868
869
870 _Tt_string
871 _tt_session_address(_Tt_object_ptr &o)
872 {
873         return ((_Tt_session *)o.c_pointer())->address_string();
874 }
875
876
877 // 
878 // Returns 1 if the given id is the same as the id of this session or if
879 // it is a process-tree id then it has the same address as this session.
880 // 
881 int _Tt_session::
882 has_id(const _Tt_string &id)
883 {
884         if (id == _id) {
885                 return(1);
886         }
887
888         if (id.len() == 0) {
889                 return(0);
890         }
891
892         if (id == _address_string) {
893                 return(1);
894         }
895
896         if (id[0] == 'P') {
897                 _Tt_string      addr = id.mid(2,id.len());
898                 return(addr == _address_string);
899         }
900
901         return(0);
902 }
903
904
905 // ...for strings list
906 int _Tt_session::
907 has_id(const _Tt_string_list_ptr slist_p)
908 {
909         _Tt_string_list_cursor c(slist_p);
910
911         while (c.next()) {
912                 if (has_id(*c)) {
913                         return(1);
914                 }
915         }
916         return(0);
917 }