mp_s_session.C 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564
  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_s_session.C /main/6 1999/09/10 19:15:11 mgreess $
  28. /*
  29. * mp_s_session.C 1.25 29 Jul 1993
  30. *
  31. * mp_s_session.cc - Server-only methods of the session object
  32. *
  33. * Copyright (c) 1990,1992 by Sun Microsystems, Inc.
  34. */
  35. #include <stdio.h>
  36. #include "mp/mp_global.h"
  37. #include "mp_s_message.h"
  38. #include "mp_s_mp.h"
  39. #include "mp/mp_mp.h"
  40. #include "mp_s_pattern.h"
  41. #include "mp_s_procid.h"
  42. #include "mp_rpc_server.h"
  43. #include "mp_rpc_implement.h"
  44. #include "mp_s_session.h"
  45. #include "mp/mp_desktop.h"
  46. #include "mp/mp_xdr_functions.h"
  47. #include "util/tt_global_env.h"
  48. #include "util/tt_host.h"
  49. #include "util/tt_enumname.h"
  50. #include "util/tt_port.h"
  51. #include "util/tt_gettext.h"
  52. #include <unistd.h>
  53. #include "util/tt_port.h"
  54. #include <X11/Xlib.h>
  55. #ifdef OPT_UNIX_SOCKET_RPC
  56. # include <sys/socket.h>
  57. # include <sys/un.h>
  58. # include "mp_rpc_server_utils.h"
  59. #endif // OPT_UNIX_SOCKET_RPC
  60. // Use the parent class (_Tt_session) for construction and destruction.
  61. _Tt_s_session::_Tt_s_session () {}
  62. _Tt_s_session::~_Tt_s_session ()
  63. {
  64. #ifdef OPT_UNIX_SOCKET_RPC
  65. if (_socket_name.len()) {
  66. // A UNIX domain socket that was bound to a pathname
  67. // and therefore must be removed by the owner when the session
  68. // server exits. This ensures that when the next session
  69. // server starts, it can choose the same pathname and bind
  70. // to it. The pathname cannot refer to a file existing
  71. // on the system.
  72. (void)unlink(_socket_name);
  73. }
  74. #endif // OPT_UNIX_SOCKET_RPC
  75. }
  76. //
  77. // Callback for i/o errors detected for the desktop session. The default
  78. // action is to exit immediately.
  79. //
  80. int
  81. _tt_xio_handler(Display * /* xdisp */)
  82. {
  83. exit(0);
  84. return 0;
  85. }
  86. #ifdef OPT_UNIX_SOCKET_RPC
  87. //
  88. // Utility routine to open a unix domain socket and bind it to the given
  89. // socket name.
  90. //
  91. // XXX: It would be more elegant to add unix domain support to the
  92. // _Tt_stream_socket class rather than have these special routines for
  93. // dealing with them.
  94. //
  95. static int
  96. s_open_unix_socket(char *socket_name)
  97. {
  98. /* open a unix socket */
  99. int sock;
  100. struct sockaddr_un server_addr;
  101. sock = socket(AF_UNIX, SOCK_STREAM, 0);
  102. if (sock < 0) {
  103. _tt_syslog(0, LOG_ERR, "s_open_unix_socket(): socket(): %m");
  104. return(-1);
  105. }
  106. memset(&server_addr, 0, sizeof(server_addr));
  107. server_addr.sun_family = AF_UNIX;
  108. (void)unlink(socket_name);
  109. strcpy(server_addr.sun_path, socket_name);
  110. #if defined(_AIX)
  111. int servlen = strlen(server_addr.sun_path) + sizeof(server_addr.sun_fam\
  112. ily);
  113. if (bind(sock, (struct sockaddr *)&server_addr,servlen) < 0) {
  114. #else
  115. if (bind(sock, (struct sockaddr *)&server_addr,
  116. sizeof(struct sockaddr_un)) < 0) {
  117. #endif
  118. return(-1);
  119. }
  120. if (listen(sock, 5) != 0) {
  121. return(-1);
  122. }
  123. return(sock);
  124. }
  125. //
  126. // Called in response to a client request for a new rpc connection. We
  127. // accept the connection on the unix socket and then use the standard
  128. // _Tt_rpc_server object, which acts accordingly if given an open file
  129. // descriptor in its constructor (see that method for more details) to
  130. // open the rpc connection.
  131. //
  132. void _Tt_s_session::
  133. u_rpc_init()
  134. {
  135. int msgsock;
  136. _Tt_rpc_server_ptr server_object;
  137. // connection request came in for the unix socket
  138. msgsock = accept(_u_sock, (struct sockaddr *)0, 0);
  139. if (msgsock == -1) {
  140. return;
  141. }
  142. server_object = new _Tt_rpc_server(_rpc_program,
  143. TT_RPC_VERSION,
  144. msgsock,
  145. _auth);
  146. if (! server_object->init(_tt_service_rpc)) {
  147. _tt_syslog(0, LOG_ERR, "u_rpc_init: server_object->init(): 0");
  148. }
  149. }
  150. #endif // OPT_UNIX_SOCKET_RPC
  151. //
  152. // This is the server-side init routine for the _Tt_session object. The
  153. // basic duties for this method are to advertise the server address
  154. // accordingly after initializing the rpc server object. If we are in a
  155. // desktop session then we first check for a session already running and
  156. // return an error code if we find one.
  157. //
  158. // Returns:
  159. // TT_OK
  160. // TT_ERR_SESSION Found a live session (diagnostic has been emitted)
  161. // TT_ERR_NOMP Could not initialize (diagnostic has been emitted)
  162. //
  163. Tt_status _Tt_s_session::
  164. s_init()
  165. {
  166. _Tt_session rsession;
  167. Tt_status status;
  168. _Tt_string h;
  169. _Tt_desktop_lock_ptr dt_lock;
  170. // this is the server session for this session
  171. _is_server = 1;
  172. if (env() == _TT_ENV_X11) {
  173. if (_displayname.len() == 0) {
  174. _displayname = _tt_global->xdisplayname;
  175. }
  176. _desktop = new _Tt_desktop();
  177. if (! _desktop->init(_displayname, _TT_DESKTOP_X11)) {
  178. return(TT_ERR_NOMP);
  179. }
  180. _desktop->set_error_handler((_Tt_dt_errfn)_tt_xio_handler);
  181. // set this field in the _Tt_s_mp object which will
  182. // then be used to add the fd for the desktop
  183. // connection to the list of fds that get polled.
  184. _tt_s_mp->xfd = _desktop->notify_fd();
  185. //
  186. // Grab the X server. The grab is in effect until
  187. // dt_lock goes out of scope (i.e., when we return).
  188. // For proper test-and-set, the grab needs to start
  189. // before check_for_live_session() and end after
  190. // advertise_address().
  191. //
  192. dt_lock = new _Tt_desktop_lock( _desktop );
  193. // check for a session already running
  194. switch (status = check_for_live_session()) {
  195. case TT_OK:
  196. case TT_ERR_NOMP:
  197. // Muscle in on dead ttsessions
  198. status = TT_OK;
  199. break;
  200. case TT_ERR_SESSION:
  201. return TT_ERR_SESSION;
  202. default:
  203. _tt_syslog(0, LOG_ERR,
  204. "_Tt_s_session::check_for_live_session(): %s",
  205. _tt_enumname(status));
  206. return TT_ERR_INTERNAL;
  207. }
  208. }
  209. _pid = getpid();
  210. _server_uid = getuid();
  211. _queued_messages = new _Tt_message_list();
  212. _properties = new _Tt_session_prop_list;
  213. // Create an RPC server managing object which will
  214. // invoke the appropiate dispatch function on any RPC
  215. // requests. This object also allocates an RPC program
  216. // number which is then used to compose the session id to
  217. // be advertised to potential clients.
  218. _rpc_server = new _Tt_rpc_server(RPC_ANYSOCK,
  219. TT_RPC_VERSION,
  220. RPC_ANYSOCK,
  221. _auth);
  222. if (! _rpc_server->init(_tt_service_rpc)) {
  223. return(TT_ERR_NOMP);
  224. }
  225. _rpc_program = _rpc_server->program();
  226. _rpc_version = _rpc_server->version();
  227. // initializes our local host object which allows us to
  228. // inquire our host address so we can then advertise it to
  229. // clients.
  230. if (! _tt_global->get_local_host(_host)) {
  231. _tt_syslog(0, LOG_ERR,"get_local_host(): 0");
  232. return(TT_ERR_NOMP);
  233. }
  234. if (parsed_address(_address_string) != TT_OK) {
  235. _tt_syslog(0, LOG_ERR,"parsed_address() != TT_OK");
  236. return(TT_ERR_NOMP);
  237. }
  238. if (_TT_AUTH_ICEAUTH == _auth.auth_level() &&
  239. (status = _auth.generate_auth_cookie()) != TT_OK) {
  240. return status;
  241. }
  242. if ((status = set_id()) == TT_OK) {
  243. // advertise our address according to the type of
  244. // session environment that we are in.
  245. if ((status = advertise_address()) == TT_OK) {
  246. #ifdef OPT_UNIX_SOCKET_RPC
  247. // open a unix domain socket for connection
  248. // requests and set the unix_fd field in the
  249. // _Tt_s_mp object to it so it can be added to
  250. // the list of file descriptors polled.
  251. _u_sock = s_open_unix_socket(local_socket_name());
  252. _tt_s_mp->unix_fd = _u_sock;
  253. #endif // OPT_UNIX_SOCKET_RPC
  254. return(TT_OK);
  255. } else {
  256. return(status);
  257. }
  258. } else {
  259. return(status);
  260. }
  261. }
  262. //
  263. // Used to check whether there is already a live session. Only desktop
  264. // sessions need this check since process-tree sessions are always unique
  265. // since they are based on the process hierarchy.
  266. //
  267. // XXX: If the range of environments were to be extended to more than
  268. // just desktop and process-tree sessions we would need more abstract
  269. // methods for session environments that return whether this check is
  270. // necessary.
  271. //
  272. // Returns:
  273. // TT_OK Found no session
  274. // TT_ERR_SESSION Found a live session (diagnostic emitted)
  275. // TT_ERR_NOMP Found a dead session (diagnostic emitted)
  276. //
  277. Tt_status _Tt_s_session::
  278. check_for_live_session()
  279. {
  280. _Tt_session rsession;
  281. Tt_status status;
  282. if (env() != _TT_ENV_X11) {
  283. return(TT_OK);
  284. }
  285. // try to find the address of an advertised session
  286. if (find_advertised_address(rsession._address_string) == TT_OK) {
  287. // found another server id, check to see that it's
  288. // running.
  289. rsession._desktop = _desktop;
  290. rsession._displayname = _displayname;
  291. status = rsession.client_session_init();
  292. switch (status) {
  293. Tt_status ping_status;
  294. case TT_OK:
  295. switch (ping_status = rsession.ping()) {
  296. case TT_OK:
  297. case TT_ERR_INVALID:
  298. case TT_ERR_NO_MATCH:
  299. case TT_ERR_UNIMP:
  300. _tt_syslog(stderr, LOG_ERR,
  301. catgets(_ttcatd, 2, 6,
  302. "Found another session run"
  303. "ning (host=%s, pid=%d)"),
  304. (char *)(rsession.host()->name()),
  305. rsession._pid);
  306. return(TT_ERR_SESSION);
  307. default:
  308. _tt_syslog(0, LOG_ERR,
  309. "_Tt_session::ping(): %s",
  310. _tt_enumname(ping_status));
  311. return TT_ERR_INTERNAL;
  312. case TT_ERR_NOMP:
  313. break; // and fall through
  314. }
  315. // Fall through
  316. case TT_ERR_NOMP:
  317. {const char *hostname = "";
  318. if (! rsession.host().is_null()) {
  319. hostname = rsession.host()->name();
  320. }
  321. _tt_syslog(stderr, LOG_ERR,
  322. catgets(_ttcatd, 2, 7,
  323. "Can't contact alleged session "
  324. "(host=%s, pid=%d); "
  325. "assuming it crashed..."),
  326. hostname, rsession._pid);
  327. return(TT_ERR_NOMP);}
  328. case TT_ERR_INVALID:
  329. _tt_syslog(stderr, LOG_ERR,
  330. catgets(_ttcatd, 2, 8,
  331. "Can't parse advertised session id;"
  332. " overwriting it with my own..."));
  333. return(TT_ERR_NOMP);
  334. case TT_WRN_NOTFOUND:
  335. case TT_ERR_ACCESS:
  336. case TT_ERR_NO_MATCH:
  337. return(TT_OK);
  338. default:
  339. _tt_syslog(0, LOG_ERR,
  340. "_Tt_session::client_session_init(): %s",
  341. _tt_enumname(status));
  342. return(TT_ERR_INTERNAL);
  343. }
  344. }
  345. return(TT_OK);
  346. }
  347. //
  348. // Advertises a session procid so that any clients that come up within
  349. // the appropiate domain will find the session id.
  350. //
  351. Tt_status _Tt_s_session::
  352. advertise_address()
  353. {
  354. _Tt_string s;
  355. _Tt_string prop(TT_XATOM_NAME);
  356. _Tt_string cde_prop(TT_CDE_XATOM_NAME);
  357. _Tt_string xdisp("DISPLAY");
  358. switch(env()) {
  359. case _TT_ENV_X11:
  360. // advertise our address by setting a special property
  361. // on our desktop session.
  362. if (_desktop->set_prop(cde_prop, _address_string) &&
  363. _desktop->set_prop(prop, _address_string)) {
  364. s = xdisp.cat("=").cat(_displayname);
  365. (void)putenv(strdup((char *)s));
  366. return(TT_OK);
  367. }
  368. return(TT_ERR_INTERNAL);
  369. case _TT_ENV_PROCESS_TREE:
  370. // advertise our address by exporting a special
  371. // environment variable.
  372. if (_tt_put_all_env_var (2, _address_string, (char*)cde_prop, (char*)prop) != 2) {
  373. return(TT_ERR_INTERNAL);
  374. }
  375. return(TT_OK);
  376. case _TT_ENV_LAST:
  377. default:
  378. return(TT_ERR_INTERNAL);
  379. }
  380. }
  381. //
  382. // This function is called to notify the session object that a new
  383. // pattern has been registered by some procid. This means that for any
  384. // queued messages, there may now be a procid that is suitable to receive
  385. // the message so this function iterates through all the queued messages
  386. // attempting to deliver the message.
  387. //
  388. // XXX: For efficiency, this method might take an argument which is the
  389. // new pattern and then delivery of the queued messages could be
  390. // restricted to just matching against the new pattern.
  391. //
  392. void _Tt_s_session::
  393. pattern_added()
  394. {
  395. _Tt_message_list_cursor qmsgs;
  396. _Tt_s_message *sm;
  397. /* try to deliver session queued msgs */
  398. qmsgs.reset(_queued_messages);
  399. while (qmsgs.next()) {
  400. sm = (_Tt_s_message *)(*qmsgs).c_pointer();
  401. // set state to "sent"
  402. sm->set_state(TT_SENT);
  403. _Tt_msg_trace trace( **qmsgs, TTDR_SESSION_JOIN );
  404. if (sm->deliver( trace )) {
  405. qmsgs.remove();
  406. } else {
  407. // couldn't successfully deliver so revert
  408. // state to queued.
  409. sm->set_state(TT_QUEUED);
  410. }
  411. }
  412. }
  413. //
  414. // The given procid wishes to join this session. We iterate through the
  415. // procid's patterns and add our session id to them. We also invoke the
  416. // pattern_added method since we may have an opportunity to deliver more
  417. // queued messages.
  418. //
  419. Tt_status _Tt_s_session::
  420. s_join(_Tt_s_procid_ptr &procid)
  421. {
  422. // update session-scoped handler patterns with session id
  423. mod_session_id_in_patterns(procid->patterns(), 1);
  424. procid->set_active(1);
  425. if (procid->is_active()) {
  426. // we've altered the patterns registered so we call
  427. // pattern_added() to attempt delivery of any
  428. // queued messages.
  429. pattern_added();
  430. }
  431. return(TT_OK);
  432. }
  433. //
  434. // For each pattern in patterns that is session-scoped, this method will
  435. // add or delete (depending on add parameter) this session's id to the
  436. // session list for the pattern.
  437. //
  438. void _Tt_s_session::
  439. mod_session_id_in_patterns(_Tt_pattern_list_ptr &patterns, int add)
  440. {
  441. _Tt_pattern_list_cursor pcursor;
  442. int scopes;
  443. pcursor.reset(patterns);
  444. while (pcursor.next()) {
  445. scopes = pcursor->scopes();
  446. if (scopes&(1<<TT_SESSION) ||
  447. scopes&(1<<TT_FILE_IN_SESSION) ||
  448. scopes&(1<<TT_BOTH)) {
  449. if (add) {
  450. pcursor->add_session(address_string());
  451. // set special pattern flag to
  452. // optimize session-scoped pattern
  453. // matching.
  454. pcursor->set_in_session();
  455. } else {
  456. pcursor->del_session(address_string());
  457. // clear special pattern flag to
  458. // optimize session-scoped pattern
  459. // matching.
  460. pcursor->clr_in_session();
  461. }
  462. }
  463. }
  464. }
  465. //
  466. // The given procid wishes to quit this session. We remove our session id
  467. // from the procid's patterns.
  468. //
  469. Tt_status _Tt_s_session::
  470. s_quit(_Tt_s_procid_ptr &procid)
  471. {
  472. // delete session from handler patterns
  473. mod_session_id_in_patterns(procid->patterns(), 0);
  474. return(TT_OK);
  475. }
  476. //
  477. // Adds a message to the queue of session-queued messages.
  478. //
  479. void _Tt_s_session::
  480. queue_message(_Tt_message_ptr &m)
  481. {
  482. if (! m->handler_ptype().len()) {
  483. // can't queue a message with no handler ptype
  484. return;
  485. }
  486. _Tt_message_list_cursor qm;
  487. Tt_state qm_state;
  488. _Tt_string qm_ptype;
  489. // verify that only one message with m's id and handler_ptype
  490. // exists in the queue (in the same state as m)
  491. qm.reset(_queued_messages);
  492. while (qm.next()) {
  493. if (qm->is_equal(m)) {
  494. qm_state = qm->state();
  495. if (qm_state == m->state()) {
  496. qm_ptype = qm->handler_ptype();
  497. if (qm_ptype == m->handler_ptype()){
  498. return;
  499. }
  500. }
  501. }
  502. }
  503. _queued_messages->append(m);
  504. }
  505. _Tt_message_list_ptr & _Tt_s_session::
  506. queued_messages()
  507. {
  508. return(_queued_messages);
  509. }