1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
4 * This file is part of tlm (Tizen Login Manager)
6 * Copyright (C) 2014 Intel Corporation.
8 * Contact: Imran Zaman <imran.zaman@intel.com>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
33 #include <sys/types.h>
36 #include "tlm-dbus-observer.h"
38 #include "tlm-utils.h"
39 #include "dbus/tlm-dbus-server-interface.h"
40 #include "dbus/tlm-dbus-server-p2p.h"
41 #include "dbus/tlm-dbus-login-adapter.h"
42 #include "dbus/tlm-dbus-utils.h"
44 #include "tlm-manager.h"
45 #include "common/tlm-error.h"
47 G_DEFINE_TYPE (TlmDbusObserver, tlm_dbus_observer, G_TYPE_OBJECT);
49 #define TLM_DBUS_OBSERVER_PRIV(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
50 TLM_TYPE_DBUS_OBSERVER, TlmDbusObserverPrivate)
54 TlmDbusRequest *dbus_request;
58 struct _TlmDbusObserverPrivate
62 TlmDbusServer *dbus_server;
63 GQueue *request_queue;
65 TlmRequest *active_request;
66 DbusObserverEnableFlags enable_flags;
70 _handle_dbus_client_added (
71 TlmDbusObserver *self,
72 GObject *dbus_adapter,
73 GObject *dbus_server);
76 _handle_dbus_client_removed (
77 TlmDbusObserver *self,
78 GObject *dbus_adapter,
79 GObject *dbus_server);
82 _handle_dbus_login_user (
83 TlmDbusObserver *self,
85 const gchar *username,
86 const gchar *password,
87 GVariant *environment,
88 GDBusMethodInvocation *invocation,
89 GObject *dbus_adapter);
92 _handle_dbus_logout_user (
93 TlmDbusObserver *self,
95 GDBusMethodInvocation *invocation,
96 GObject *dbus_adapter);
99 _handle_dbus_switch_user (
100 TlmDbusObserver *self,
101 const gchar *seat_id,
102 const gchar *username,
103 const gchar *password,
104 GVariant *environment,
105 GDBusMethodInvocation *invocation,
106 GObject *dbus_adapter);
109 _disconnect_dbus_adapter (
110 TlmDbusObserver *self,
111 TlmDbusLoginAdapter *adapter);
114 _handle_seat_session_created (
115 TlmDbusObserver *self,
116 const gchar *seat_id,
120 _handle_seat_session_terminated (
121 TlmDbusObserver *self,
122 const gchar *seat_id,
126 _handle_seat_session_error (
127 TlmDbusObserver *self,
133 TlmDbusObserver *self,
138 TlmDbusObserver *self,
142 _process_next_request_in_idle (
143 TlmDbusObserver *self);
147 TlmDbusObserver *self,
150 g_return_if_fail (self && TLM_IS_DBUS_OBSERVER(self) && dead &&
152 g_object_weak_unref (dead, (GWeakNotify)_on_seat_dispose, self);
153 _disconnect_seat (self, TLM_SEAT (dead));
154 if (self->priv->active_request &&
155 G_OBJECT(self->priv->active_request->seat) == dead) {
156 self->priv->active_request->seat = NULL;
158 if (G_OBJECT(self->priv->seat) == dead)
159 self->priv->seat = NULL;
163 _on_manager_dispose (
164 TlmDbusObserver *self,
167 g_return_if_fail (self && TLM_IS_DBUS_OBSERVER(self) && dead &&
168 TLM_IS_MANAGER(dead));
169 g_object_weak_unref (dead, (GWeakNotify)_on_manager_dispose, self);
170 self->priv->manager = NULL;
175 TlmDbusObserver *self,
176 TlmDbusRequest *dbus_req,
179 TlmRequest *request = g_malloc0 (sizeof (TlmRequest));
180 if (!request) return NULL;
182 request->dbus_request = dbus_req;
183 request->seat = seat;
185 _connect_seat (self, request->seat);
186 g_object_weak_ref (G_OBJECT (request->seat),
187 (GWeakNotify)_on_seat_dispose, self);
194 TlmDbusObserver *self,
197 if (!request) return;
199 if (request->dbus_request) {
200 tlm_dbus_login_adapter_request_completed (request->dbus_request, NULL);
201 tlm_dbus_utils_dispose_request (request->dbus_request);
202 request->dbus_request = NULL;
205 _disconnect_seat (self, request->seat);
206 g_object_weak_unref (G_OBJECT (request->seat),
207 (GWeakNotify)_on_seat_dispose, self);
208 request->seat = NULL;
215 TlmDbusObserver *self,
218 DBG ("self %p seat %p", self, seat);
221 g_signal_handlers_disconnect_by_func (G_OBJECT (seat),
222 _handle_seat_session_created, self);
223 g_signal_handlers_disconnect_by_func (G_OBJECT (seat),
224 _handle_seat_session_terminated, self);
225 g_signal_handlers_disconnect_by_func (G_OBJECT (seat),
226 _handle_seat_session_error, self);
231 TlmDbusObserver *self,
234 DBG ("self %p seat %p", self, seat);
237 g_signal_connect_swapped (G_OBJECT (seat), "session-created",
238 G_CALLBACK(_handle_seat_session_created), self);
239 g_signal_connect_swapped (G_OBJECT (seat), "session-terminated",
240 G_CALLBACK(_handle_seat_session_terminated), self);
241 g_signal_connect_swapped (G_OBJECT (seat), "session-error",
242 G_CALLBACK(_handle_seat_session_error), self);
246 _on_dbus_adapter_dispose (
247 TlmDbusObserver *self,
250 GList *head=NULL, *elem=NULL, *next;
252 g_return_if_fail (self && TLM_IS_DBUS_OBSERVER(self) && dead &&
253 TLM_IS_DBUS_LOGIN_ADAPTER(dead));
254 _disconnect_dbus_adapter (self, TLM_DBUS_LOGIN_ADAPTER(dead));
256 if (self->priv->request_queue)
257 head = elem = g_queue_peek_head_link (self->priv->request_queue);
259 TlmRequest *request = elem->data;
260 TlmDbusRequest *dbus_req = request->dbus_request;
261 next = g_list_next (elem);
262 if (dbus_req && G_OBJECT (dbus_req->dbus_adapter) == dead) {
263 DBG ("removing the request for dead dbus adapter");
264 head = g_list_delete_link (head, elem);
265 _dispose_request (self, request);
270 /* check for active request */
271 if (self->priv->active_request &&
272 G_OBJECT (self->priv->active_request->dbus_request->dbus_adapter) ==
274 DBG ("removing the request for dead dbus adapter");
275 _dispose_request (self, self->priv->active_request);
276 self->priv->active_request = NULL;
277 if (self->priv->request_id) {
278 g_source_remove (self->priv->request_id);
279 self->priv->request_id = 0;
281 _process_next_request_in_idle (self);
286 _connect_dbus_adapter (
287 TlmDbusObserver *self,
288 TlmDbusLoginAdapter *adapter)
290 if (self->priv->enable_flags & DBUS_OBSERVER_ENABLE_LOGIN_USER)
291 g_signal_connect_swapped (G_OBJECT (adapter),
292 "login-user", G_CALLBACK(_handle_dbus_login_user), self);
293 if (self->priv->enable_flags & DBUS_OBSERVER_ENABLE_LOGOUT_USER)
294 g_signal_connect_swapped (G_OBJECT (adapter),
295 "logout-user", G_CALLBACK(_handle_dbus_logout_user), self);
296 if (self->priv->enable_flags & DBUS_OBSERVER_ENABLE_SWITCH_USER)
297 g_signal_connect_swapped (G_OBJECT (adapter),
298 "switch-user", G_CALLBACK(_handle_dbus_switch_user), self);
302 _disconnect_dbus_adapter (
303 TlmDbusObserver *self,
304 TlmDbusLoginAdapter *adapter)
306 if (self->priv->enable_flags & DBUS_OBSERVER_ENABLE_LOGIN_USER)
307 g_signal_handlers_disconnect_by_func (G_OBJECT(adapter),
308 _handle_dbus_login_user, self);
309 if (self->priv->enable_flags & DBUS_OBSERVER_ENABLE_LOGOUT_USER)
310 g_signal_handlers_disconnect_by_func (G_OBJECT(adapter),
311 _handle_dbus_logout_user, self);
312 if (self->priv->enable_flags & DBUS_OBSERVER_ENABLE_SWITCH_USER)
313 g_signal_handlers_disconnect_by_func (G_OBJECT(adapter),
314 _handle_dbus_switch_user, self);
318 _handle_dbus_client_added (
319 TlmDbusObserver *self,
320 GObject *dbus_adapter,
321 GObject *dbus_server)
323 g_return_if_fail (self && TLM_IS_DBUS_OBSERVER(self) && dbus_adapter &&
324 TLM_IS_DBUS_LOGIN_ADAPTER(dbus_adapter));
325 _connect_dbus_adapter (self, TLM_DBUS_LOGIN_ADAPTER(dbus_adapter));
326 g_object_weak_ref (G_OBJECT (dbus_adapter),
327 (GWeakNotify)_on_dbus_adapter_dispose, self);
331 _handle_dbus_client_removed (
332 TlmDbusObserver *self,
333 GObject *dbus_adapter,
334 GObject *dbus_server)
336 g_return_if_fail (self && TLM_IS_DBUS_OBSERVER(self) && dbus_adapter &&
337 TLM_IS_DBUS_LOGIN_ADAPTER(dbus_adapter));
338 _disconnect_dbus_adapter (self, TLM_DBUS_LOGIN_ADAPTER(dbus_adapter));
339 g_object_weak_unref (G_OBJECT (dbus_adapter),
340 (GWeakNotify)_on_dbus_adapter_dispose, self);
344 _complete_dbus_request (
345 TlmDbusRequest *request,
349 tlm_dbus_login_adapter_request_completed (request, error);
350 tlm_dbus_utils_dispose_request (request);
352 if (error) g_error_free (error);
356 _abort_dbus_request (
357 TlmDbusRequest *request)
359 if (!request) return;
361 GError *error = TLM_GET_ERROR_FOR_ID (TLM_ERROR_DBUS_REQ_ABORTED,
362 "Dbus request aborted");
363 _complete_dbus_request (request, error);
368 TlmDbusObserver *self,
372 _complete_dbus_request (request->dbus_request, error);
373 request->dbus_request = NULL;
374 _dispose_request (self, request);
380 TlmDbusObserver *self)
382 if (!request) return;
384 _abort_dbus_request (request->dbus_request);
385 request->dbus_request = NULL;
386 _dispose_request (self, request);
390 _is_request_supported (
391 TlmDbusObserver *self,
392 TlmDbusRequestType req_type)
395 case TLM_DBUS_REQUEST_TYPE_LOGIN_USER:
396 return (self->priv->enable_flags & DBUS_OBSERVER_ENABLE_LOGIN_USER);
397 case TLM_DBUS_REQUEST_TYPE_LOGOUT_USER:
398 return (self->priv->enable_flags & DBUS_OBSERVER_ENABLE_LOGOUT_USER);
399 case TLM_DBUS_REQUEST_TYPE_SWITCH_USER:
400 return (self->priv->enable_flags & DBUS_OBSERVER_ENABLE_SWITCH_USER);
407 TlmDbusObserver *self)
409 g_return_val_if_fail (self && TLM_IS_DBUS_OBSERVER(self), FALSE);
411 TlmRequest* req = NULL;
412 TlmDbusRequest* dbus_req = NULL;
413 TlmSeat *seat = NULL;
415 self->priv->request_id = 0;
417 if (!self->priv->active_request) {
418 gboolean ret = FALSE;
420 req = g_queue_pop_head (self->priv->request_queue);
422 DBG ("request queue is empty");
425 dbus_req = req->dbus_request;
426 if (!_is_request_supported (self, dbus_req->type)) {
427 WARN ("Request not supported -- req-type %d flags %d",
428 dbus_req->type, self->priv->enable_flags);
429 err = TLM_GET_ERROR_FOR_ID (TLM_ERROR_DBUS_REQ_NOT_SUPPORTED,
430 "Dbus request not supported");
434 seat = self->priv->seat;
435 if (!seat && self->priv->manager) {
436 seat = tlm_manager_get_seat (self->priv->manager,
439 /* NOTE: When no seat is set at dbus object creation time,
440 * seat is connected on per dbus request basis and then
441 * disconnected when the dbus request is completed or aborted */
443 _connect_seat (self, seat);
444 g_object_weak_ref (G_OBJECT (seat),
445 (GWeakNotify)_on_seat_dispose, self);
450 WARN ("Cannot find the seat");
451 err = TLM_GET_ERROR_FOR_ID (TLM_ERROR_SEAT_NOT_FOUND,
456 self->priv->active_request = req;
457 switch(dbus_req->type) {
458 case TLM_DBUS_REQUEST_TYPE_LOGIN_USER:
459 ret = tlm_seat_create_session (seat, NULL, dbus_req->username,
460 dbus_req->password, dbus_req->environment);
462 case TLM_DBUS_REQUEST_TYPE_LOGOUT_USER:
463 ret = tlm_seat_terminate_session (seat);
465 case TLM_DBUS_REQUEST_TYPE_SWITCH_USER:
466 ret = tlm_seat_switch_user (seat, NULL, dbus_req->username,
467 dbus_req->password, dbus_req->environment);
471 _dispose_request (self, self->priv->active_request);
472 self->priv->active_request = NULL;
479 _complete_request (self, req, err);
484 if (!self->priv->active_request)
485 _process_next_request_in_idle (self);
491 _process_next_request_in_idle (
492 TlmDbusObserver *self)
494 if (!self->priv->request_id &&
495 !g_queue_is_empty (self->priv->request_queue)) {
496 DBG ("request queue has request(s) to be processed");
497 self->priv->request_id = g_idle_add ((GSourceFunc)_process_request,
504 TlmDbusObserver *self,
507 g_queue_push_tail (self->priv->request_queue, request);
508 _process_next_request_in_idle (self);
512 _handle_seat_session_created (
513 TlmDbusObserver *self,
514 const gchar *seat_id,
517 DBG ("self %p seat %p", self, seat);
519 g_return_if_fail (self && TLM_IS_DBUS_OBSERVER(self));
520 g_return_if_fail (seat && TLM_IS_SEAT(seat));
522 /* Login/switch request should only be completed on session created
523 * signal from seat */
524 if (!self->priv->active_request ||
525 !self->priv->active_request->dbus_request ||
526 self->priv->active_request->dbus_request->type ==
527 TLM_DBUS_REQUEST_TYPE_LOGOUT_USER)
530 _complete_request (self, self->priv->active_request, NULL);
531 self->priv->active_request = NULL;
533 _process_next_request_in_idle (self);
537 _handle_seat_session_terminated (
538 TlmDbusObserver *self,
539 const gchar *seat_id,
542 DBG ("self %p seat %p", self, seat);
544 g_return_val_if_fail (self && TLM_IS_DBUS_OBSERVER(self), FALSE);
545 g_return_val_if_fail (seat && TLM_IS_SEAT(seat), FALSE);
547 /* Logout request should only be completed on session terminated signal
549 if (!self->priv->active_request ||
550 !self->priv->active_request->dbus_request ||
551 self->priv->active_request->dbus_request->type !=
552 TLM_DBUS_REQUEST_TYPE_LOGOUT_USER)
555 _disconnect_dbus_adapter (self, TLM_DBUS_LOGIN_ADAPTER (
556 self->priv->active_request->dbus_request->dbus_adapter));
558 _complete_request (self, self->priv->active_request, NULL);
559 self->priv->active_request = NULL;
561 _process_next_request_in_idle (self);
567 _handle_seat_session_error (
568 TlmDbusObserver *self,
572 DBG ("self %p seat %p", self, seat);
573 GError *error = NULL;
575 g_return_if_fail (self && TLM_IS_DBUS_OBSERVER(self));
576 g_return_if_fail (seat && TLM_IS_SEAT(seat));
578 if (!self->priv->active_request)
581 error = TLM_GET_ERROR_FOR_ID (error_code, "Dbus request failed");
582 _complete_request (self, self->priv->active_request, error);
583 self->priv->active_request = NULL;
585 _process_next_request_in_idle (self);
589 _handle_dbus_login_user (
590 TlmDbusObserver *self,
591 const gchar *seat_id,
592 const gchar *username,
593 const gchar *password,
594 GVariant *environment,
595 GDBusMethodInvocation *invocation,
596 GObject *dbus_adapter)
598 TlmDbusRequest *request = NULL;
600 DBG ("seat id %s, username %s", seat_id, username);
601 g_return_if_fail (self && TLM_IS_DBUS_OBSERVER(self));
603 request = tlm_dbus_utils_create_request (dbus_adapter, invocation,
604 TLM_DBUS_REQUEST_TYPE_LOGIN_USER, seat_id, username, password,
606 _add_request (self, _create_request (self, request, NULL));
610 _handle_dbus_logout_user (
611 TlmDbusObserver *self,
612 const gchar *seat_id,
613 GDBusMethodInvocation *invocation,
614 GObject *dbus_adapter)
616 TlmDbusRequest *request = NULL;
618 DBG ("seat id %s", seat_id);
619 g_return_if_fail (self && TLM_IS_DBUS_OBSERVER(self));
621 request = tlm_dbus_utils_create_request (dbus_adapter, invocation,
622 TLM_DBUS_REQUEST_TYPE_LOGOUT_USER, seat_id, NULL, NULL, NULL);
623 _add_request (self, _create_request (self, request, NULL));
627 _handle_dbus_switch_user (
628 TlmDbusObserver *self,
629 const gchar *seat_id,
630 const gchar *username,
631 const gchar *password,
632 GVariant *environment,
633 GDBusMethodInvocation *invocation,
634 GObject *dbus_adapter)
636 TlmDbusRequest *request = NULL;
638 DBG ("seat id %s, username %s", seat_id, username);
639 g_return_if_fail (self && TLM_IS_DBUS_OBSERVER(self));
641 request = tlm_dbus_utils_create_request (dbus_adapter, invocation,
642 TLM_DBUS_REQUEST_TYPE_SWITCH_USER, seat_id, username, password,
644 _add_request (self, _create_request (self, request, NULL));
648 _stop_dbus_server (TlmDbusObserver *self)
650 DBG("self %p", self);
651 _clear_request (self->priv->active_request, self);
652 self->priv->active_request = NULL;
654 if (self->priv->request_queue) {
655 g_queue_foreach (self->priv->request_queue,
656 (GFunc) _clear_request, self);
657 g_queue_free (self->priv->request_queue);
658 self->priv->request_queue = NULL;
661 if (self->priv->dbus_server) {
662 tlm_dbus_server_stop (self->priv->dbus_server);
663 g_object_unref (self->priv->dbus_server);
664 self->priv->dbus_server = NULL;
670 TlmDbusObserver *self,
671 const gchar *address,
674 DBG("self %p address %s uid %d", self, address, uid);
675 self->priv->dbus_server = TLM_DBUS_SERVER (tlm_dbus_server_p2p_new (address,
677 return tlm_dbus_server_start (self->priv->dbus_server);
681 tlm_dbus_observer_dispose (GObject *object)
683 TlmDbusObserver *self = TLM_DBUS_OBSERVER(object);
684 DBG("disposing dbus_observer: %p", self);
686 if (self->priv->request_id) {
687 g_source_remove (self->priv->request_id);
688 self->priv->request_id = 0;
691 _stop_dbus_server (self);
692 if (self->priv->manager) {
693 g_object_weak_unref (G_OBJECT (self->priv->manager),
694 (GWeakNotify)_on_manager_dispose, self);
695 self->priv->manager = NULL;
698 if (self->priv->seat) {
699 g_object_weak_unref (G_OBJECT (self->priv->seat),
700 (GWeakNotify)_on_seat_dispose, self);
701 self->priv->seat = NULL;
703 DBG("disposing dbus_observer DONE: %p", self);
705 G_OBJECT_CLASS (tlm_dbus_observer_parent_class)->dispose (object);
709 tlm_dbus_observer_finalize (GObject *self)
711 //TlmDbusObserver *dbus_observer = TLM_DBUS_OBSERVER(self);
713 G_OBJECT_CLASS (tlm_dbus_observer_parent_class)->finalize (self);
717 tlm_dbus_observer_class_init (TlmDbusObserverClass *klass)
719 GObjectClass *g_klass = G_OBJECT_CLASS (klass);
721 g_type_class_add_private (klass, sizeof (TlmDbusObserverPrivate));
723 g_klass->dispose = tlm_dbus_observer_dispose ;
724 g_klass->finalize = tlm_dbus_observer_finalize;
728 tlm_dbus_observer_init (TlmDbusObserver *dbus_observer)
730 TlmDbusObserverPrivate *priv = TLM_DBUS_OBSERVER_PRIV (dbus_observer);
732 priv->manager = NULL;
734 priv->enable_flags = DBUS_OBSERVER_ENABLE_ALL;
735 priv->request_queue = g_queue_new ();
736 priv->request_id = 0;
737 priv->active_request = NULL;
738 dbus_observer->priv = priv;
742 tlm_dbus_observer_new (
745 const gchar *address,
747 DbusObserverEnableFlags enable_flags)
749 TlmDbusObserver *dbus_observer =
750 g_object_new (TLM_TYPE_DBUS_OBSERVER, NULL);
751 DBG ("%p", dbus_observer);
754 dbus_observer->priv->manager = manager;
755 g_object_weak_ref (G_OBJECT (manager), (GWeakNotify)_on_manager_dispose,
758 /* NOTE: When no seat is set at dbus object creation time,
759 * seat is connected on per dbus request basis and then
760 * disconnected when the dbus request is completed or aborted */
762 dbus_observer->priv->seat = seat;
763 g_object_weak_ref (G_OBJECT (seat), (GWeakNotify)_on_seat_dispose,
766 dbus_observer->priv->enable_flags = enable_flags;
768 if (!_start_dbus_server (dbus_observer, address, uid)) {
769 WARN ("DbusObserver startup failed");
770 g_object_unref (dbus_observer);
774 g_signal_connect_swapped (dbus_observer->priv->dbus_server,
775 "client-added", G_CALLBACK (_handle_dbus_client_added),
777 g_signal_connect_swapped (dbus_observer->priv->dbus_server,
778 "client-removed", G_CALLBACK(_handle_dbus_client_removed),
780 return dbus_observer;