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