cedc2ca2f29720cef2d83f5d6b6e45d91337c4e8
[oweals/cde.git] / cde / lib / tt / lib / mp / mp_c_session.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 libraries 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 //%%  $TOG: mp_c_session.C /main/5 1999/10/14 18:41:24 mgreess $                                                        
28 /*
29  *  @(#)mp_c_session.C  1.23    94/10/03
30  *
31  *  Copyright (c) 1990,1992,1993 by Sun Microsystems, Inc.
32  *
33  *  Implementation of the _Tt_session class.
34  */
35 #include "util/tt_global_env.h"
36 #include "util/tt_host.h"
37 #include "util/tt_enumname.h"
38 #include "mp/mp_global.h"
39 #include "mp/mp_c_message.h"
40 #include "mp/mp_mp.h"
41 #include "mp/mp_pattern.h"
42 #include "mp/mp_rpc_client.h"
43 #include "mp/mp_rpc_interface.h"
44 #include "mp/mp_c_session.h"
45 #include "mp/mp_desktop.h"
46 #include "mp/mp_xdr_functions.h"
47 #include "util/tt_port.h"
48 #include <unistd.h>
49 #include <signal.h>
50
51 #ifdef OPT_UNIX_SOCKET_RPC
52 #       include <sys/socket.h>
53 #       include <sys/un.h>
54 #endif // OPT_UNIX_SOCKET_RPC
55      
56 // Use the parent class (_Tt_session) for construction and destruction.
57 _Tt_c_session::_Tt_c_session () {}
58 _Tt_c_session::~_Tt_c_session () {}
59
60
61
62 // 
63 // Initializes a session object. This means that we initialize our
64 // desktop connection if this is a desktop session and find the address
65 // of a server session. If none is found or if an address is found but we
66 // are unable to connect to the session then we attempt to auto-start a
67 // server session. 
68 //
69 // Returns:
70 //      TT_OK
71 //      TT_ERR_ACCESS   Could not init desktop (diagnostic emitted)
72 //      TT_ERR_NO_MATCH Advertised address's version is too new
73 //                      (diagnostic emitted)
74 //      TT_ERR_INVALID  Authorization error
75 //      TT_ERR_NOMP     No server running or startable
76 // 
77 Tt_status _Tt_c_session::
78 c_init()
79 {
80         _Tt_string      start_ttcmd;
81         int             tried = 0;
82         Tt_status       status;
83
84         if (env() == _TT_ENV_X11) {
85                 if (_displayname.len() == 0) {
86                         _displayname = _tt_global->xdisplayname;
87                 }
88         }
89         while (tried < 10) {
90                 _is_dead = 0;
91                 status = client_session_init();
92                 switch (status) {
93                         int pings;
94                     case TT_OK:
95                         // We try to ping the session to give it
96                         // reasonable time to start up.
97                         for (pings = 1; pings <= OPT_PING_TRIES; pings++) {
98                                 status = ping();
99                                 if (status != TT_ERR_NOMP) {
100                                         // Fatal error or TT_OK
101                                         return status;
102                                 }
103                                 sleep(OPT_PING_SLEEP);
104                         }
105
106                         // Session could not be pinged.  If this is an
107                         // X11 session, handle the case where there is
108                         // an invalid TT_CDE_XATOM_NAME xprop and a valid
109                         // TT_XATOM_NAME xprop, because in that case we
110                         // were trying to ping the dead TT_CDE_XATOM_NAME
111                         // session.
112
113                         if (env() == _TT_ENV_X11) {
114                                 _Tt_string desktop_addr;
115
116                                 if (_desktop->get_prop(TT_CDE_XATOM_NAME,
117                                                        desktop_addr) &&
118                                     desktop_addr == _address_string) {
119
120                                         // Bogus session xprop found -- re-initialize
121                                         // trying the TT_XATOM_NAME xprop.
122
123                                         if (_desktop->get_prop(TT_XATOM_NAME,
124                                                                _address_string)) {
125                                                 // Continue the initialization
126                                                 // loop WITHOUT attempting to start
127                                                 // a new ttsession
128                                                 tried++;
129                                                 continue;
130                                         }
131                                 }
132                         }
133                         else {
134                                 // If we\'re here, a session was found but could
135                                 // not be pinged.  Force re-initialization.
136                                 _address_string = (char *) 0;
137                                 break;
138                         }
139                     case TT_ERR_ACCESS:
140                     case TT_ERR_NO_MATCH:
141                         // Can't recover from these
142                         return status;
143                     case TT_WRN_NOTFOUND:
144                     case TT_ERR_INVALID:
145                     case TT_ERR_NOMP:
146                         // No ttsession.
147                         // If we haven\'t tried to start one already, do
148                         // so. If we have tried but failed, force
149                         // client_session_init to re-initialize.
150                         if (tried > 0) _address_string = (char *) 0;
151                         break;
152                     case TT_AUTHFILE_ACCESS:
153                     case TT_AUTHFILE_LOCK:
154                     case TT_AUTHFILE_LOCK_TIMEOUT:
155                     case TT_AUTHFILE_UNLOCK:
156                     case TT_AUTHFILE_MISSING:
157                     case TT_AUTHFILE_ENTRY_MISSING:
158                     case TT_AUTHFILE_WRITE:
159                         return TT_ERR_AUTHORIZATION;
160                     default:
161                         _tt_syslog( 0, LOG_ERR,
162                                     "_Tt_session::client_session_init(): %s",
163                                     _tt_enumname(status));
164                         return TT_ERR_INTERNAL;
165                 }
166                 //
167                 // Attempt to start a new server
168                 //
169                 if (env() != _TT_ENV_X11) {
170                         // can't auto-start anything other than an X
171                         // tooltalk session
172                         return TT_ERR_NOMP;
173                 }
174                 if (tried == 0) {
175                         int sysStat = startup_ttsession(start_ttcmd);
176                         int exitStat;
177                         if (WIFEXITED(sysStat)) {
178                                 exitStat = WEXITSTATUS(sysStat);
179                         } else if (WIFSIGNALED(sysStat)) {
180                                 _tt_syslog( 0, LOG_ERR,
181                                             "libtt: system(\"%s\"): signal %d",
182                                             (char *)start_ttcmd,
183                                             WTERMSIG(sysStat) );
184                                 exitStat = 11;
185                         } else {
186                                 _tt_syslog( 0, LOG_ERR,
187                                             "libtt: system(\"%s\"): %d",
188                                             (char *)start_ttcmd, sysStat );
189                                 exitStat = 11;
190                         }
191                         switch (exitStat) {
192                             case 1:
193                                 // Race condition -- no ttsession was
194                                 // found in the above code, but by the time
195                                 // we got around to trying to start one,
196                                 // another had appeared, so this one exited
197                                 // normally.
198                                 // Fall through.
199                             case 2:
200                                 // another ttsession discovered.
201                                 // Either way, loop around and connect to it
202                                 // after nulling _address_string to make sure
203                                 // we pick the address off the X server again
204                                 // since the new server will have a new
205                                 // address.
206                                 _address_string = (char *)0;
207
208                                 // Since the other ttsession was just started,
209                                 // let it have a chance to initialize
210                                 sleep(2);
211
212                                 // fall through
213                             case 0:
214                                 // ttsession started.
215                                 break;
216                             default:
217                                 return TT_ERR_NOMP;
218                         }
219                 } else {
220                         sleep(1);
221                 }
222                 tried++;
223         }
224
225         return TT_ERR_NOMP;
226 }
227
228 // Starts ttsession by executing either the hardcoded
229 // default command "ttsession -s -d <displayname>"
230 // or the command specified in TTSESSION_CMD or SUN_TTSESSION_CMD.
231 // TTSESSION_CMD and SUN_TTSESSION_CMD provide a way of overriding the
232 // standard options specified when tools auto-start
233 // ttsession. For example, to switch from Classing
234 // Engine format to xdr format for auto-start set
235 // TTSESSION_CMD or SUN_TTSESSION_CMD to "ttsession -X".
236 // The string used is returned in a parameter so c_init can use it in
237 // error messages.
238
239
240 int _Tt_c_session::
241 startup_ttsession(_Tt_string &start_ttcmd)
242 {
243         // If TTSESSION_CMD or SUN_TTSESSION_CMD is specified, we use system() to run the
244         // command since it might have shell metacharacters (a common
245         // thing to do is TTSESSION_CMD or SUN_TTSESSION_CMD=truss ttsession >/tmp/trace
246         // in order to truss ttsession startup)
247
248     char* pc_env_value = _tt_get_first_set_env_var(2, "TTSESSION_CMD", "SUN_TTSESSION_CMD");
249
250         if (pc_env_value) {
251                 start_ttcmd = pc_env_value;
252                 start_ttcmd = start_ttcmd.cat(" -d ");
253                 start_ttcmd = start_ttcmd.cat(_displayname);
254                 return system((char *)start_ttcmd);
255         }
256         // start_ttcmd is not really used but we set it so it can be used
257         // in messages
258         start_ttcmd = "ttsession -s -d ";
259         start_ttcmd = start_ttcmd.cat(_displayname);
260         
261         // This is basically a stripped down and specialized system() call...
262
263         int     status;
264         pid_t   pid, w;
265
266 #if defined(__GNUG__)
267         typedef void (*SIG_PF)(int);
268 #endif
269         SIG_PF istat, qstat, cstat;
270
271 #if defined(_AIX) || defined(OPT_BUG_USL) || defined(OPT_BUG_UXP)
272 #define vfork fork
273 #endif
274         if((pid = vfork()) == 0) {
275                 fflush(stdout);
276                 (void) execlp("ttsession", "ttsession",
277                               "-s",
278                               "-d",
279                               (char *)_displayname,
280                               (char *)0);
281                 _exit(127);
282         }
283
284         istat = signal(SIGINT, SIG_IGN);
285         qstat = signal(SIGQUIT, SIG_IGN);
286         cstat = signal(SIGCHLD, SIG_DFL);
287
288         w = waitpid(pid, &status, 0);
289
290         (void) signal(SIGINT, istat);
291         (void) signal(SIGQUIT, qstat);
292         (void) signal(SIGCHLD, cstat);
293
294         return((w == -1)? w: status);
295         
296 }
297
298 //
299 // Invokes an rpc call on the server session that causes all of the
300 // given procid's patterns to have a session id for the current
301 // session (this allows them to begin matching messages).
302 //
303 // See _Tt_s_session::s_join for the server-side of this method.
304 //
305 Tt_status _Tt_c_session::
306 c_join(_Tt_procid_ptr &procid)
307 {
308         Tt_status               status;
309         Tt_status               rstatus;
310
311         rstatus = call(TT_RPC_JOIN_SESSION,
312                        (xdrproc_t)tt_xdr_procid,
313                        (char *)&procid,
314                        (xdrproc_t)xdr_int,
315                        (char *)&status);
316         return((rstatus == TT_OK) ? status : rstatus);
317 }
318
319
320 //
321 // Invokes an rpc call on the server session that causes all of the
322 // given procid's patterns to not have a session id for the current
323 // session (this prevents them from matching messages).
324 //
325 // See _Tt_s_session::s_quit for the server-side of this method.
326 //
327 Tt_status _Tt_c_session::
328 c_quit(_Tt_procid_ptr &procid)
329 {
330         Tt_status               status;
331         Tt_status               rstatus;
332                 
333         rstatus = call(TT_RPC_QUIT_SESSION,
334                        (xdrproc_t)tt_xdr_procid, (char *)&procid,
335                        (xdrproc_t)xdr_int, (char *)&status);
336         return((rstatus == TT_OK) ? status : rstatus);
337 }