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
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, but
16 * 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
27 #include <glib/gstdio.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
34 #include "common/dbus/tlm-dbus.h"
35 #include "common/tlm-log.h"
37 #include "tlm-dbus-server-p2p.h"
38 #include "tlm-dbus-server-interface.h"
39 #include "tlm-dbus-login-adapter.h"
58 static guint signals[SIG_MAX];
60 struct _TlmDbusServerP2PPrivate
62 GHashTable *login_object_adapters;
63 GDBusServer *bus_server;
69 _tlm_dbus_server_p2p_interface_init (
70 TlmDbusServerInterface *iface);
73 _tlm_dbus_server_p2p_stop (
77 _on_connection_closed (
78 GDBusConnection *connection,
79 gboolean remote_peer_vanished,
83 G_DEFINE_TYPE_WITH_CODE (TlmDbusServerP2P,
84 tlm_dbus_server_p2p, G_TYPE_OBJECT,
85 G_IMPLEMENT_INTERFACE (TLM_TYPE_DBUS_SERVER,
86 _tlm_dbus_server_p2p_interface_init));
88 #define TLM_DBUS_SERVER_P2P_GET_PRIV(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
89 TLM_TYPE_DBUS_SERVER_P2P, TlmDbusServerP2PPrivate)
98 TlmDbusServerP2P *self = TLM_DBUS_SERVER_P2P (object);
99 switch (property_id) {
100 case IFACE_PROP_TYPE: {
104 self->priv->address = g_value_dup_string (value);
108 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
119 TlmDbusServerP2P *self = TLM_DBUS_SERVER_P2P (object);
121 switch (property_id) {
122 case IFACE_PROP_TYPE: {
123 g_value_set_uint (value, (guint)TLM_DBUS_SERVER_BUSTYPE_P2P);
127 g_value_set_string (value, g_dbus_server_get_client_address (
128 self->priv->bus_server));
132 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
137 _compare_by_pointer (
140 gpointer dead_object)
142 return value == dead_object;
146 _on_login_object_dispose (
150 TlmDbusServerP2P *server = TLM_DBUS_SERVER_P2P (data);
151 g_return_if_fail (server);
152 g_hash_table_foreach_steal (server->priv->login_object_adapters,
153 _compare_by_pointer, dead);
157 _clear_login_object_watchers (
159 gpointer login_object,
162 g_signal_handlers_disconnect_by_func (connection, _on_connection_closed,
164 g_object_weak_unref (G_OBJECT(login_object), _on_login_object_dispose,
169 _add_login_object_watchers (
171 gpointer login_object,
172 TlmDbusServerP2P *server)
174 g_signal_connect (connection, "closed", G_CALLBACK(_on_connection_closed),
176 g_object_weak_ref (G_OBJECT (login_object), _on_login_object_dispose,
178 g_hash_table_insert (server->priv->login_object_adapters, connection,
186 TlmDbusServerP2P *self = TLM_DBUS_SERVER_P2P (object);
188 _tlm_dbus_server_p2p_stop (TLM_DBUS_SERVER (self));
190 G_OBJECT_CLASS (tlm_dbus_server_p2p_parent_class)->dispose (object);
197 TlmDbusServerP2P *self = TLM_DBUS_SERVER_P2P (object);
198 if (self->priv->address) {
199 if (g_str_has_prefix (self->priv->address, "unix:path=")) {
200 const gchar *path = g_strstr_len(self->priv->address, -1,
206 g_free (self->priv->address);
207 self->priv->address = NULL;
209 G_OBJECT_CLASS (tlm_dbus_server_p2p_parent_class)->finalize (object);
213 tlm_dbus_server_p2p_class_init (
214 TlmDbusServerP2PClass *klass)
216 GObjectClass* object_class = G_OBJECT_CLASS (klass);
217 GParamSpec *address_spec = NULL;
219 g_type_class_add_private (object_class, sizeof (TlmDbusServerP2PPrivate));
221 object_class->get_property = _get_property;
222 object_class->set_property = _set_property;
223 object_class->dispose = _dispose;
224 object_class->finalize = _finalize;
226 g_object_class_override_property (object_class, IFACE_PROP_TYPE, "bustype");
228 address_spec = g_param_spec_string ("address", "server address",
229 "Server socket address", NULL,
230 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
231 G_PARAM_STATIC_STRINGS);
232 g_object_class_install_property (object_class, PROP_ADDRESS, address_spec);
234 signals[SIG_CLIENT_ADDED] = g_signal_new ("client-added",
235 TLM_TYPE_DBUS_SERVER_P2P,
243 TLM_TYPE_LOGIN_ADAPTER);
245 signals[SIG_CLIENT_REMOVED] = g_signal_new ("client-removed",
246 TLM_TYPE_DBUS_SERVER_P2P,
254 TLM_TYPE_LOGIN_ADAPTER);
258 tlm_dbus_server_p2p_init (
259 TlmDbusServerP2P *self)
261 self->priv = TLM_DBUS_SERVER_P2P_GET_PRIV(self);
262 self->priv->bus_server = NULL;
263 self->priv->address = NULL;
265 self->priv->login_object_adapters = g_hash_table_new_full (g_direct_hash,
266 g_direct_equal, NULL, g_object_unref);
270 _on_connection_closed (
271 GDBusConnection *connection,
272 gboolean remote_peer_vanished,
276 TlmDbusServerP2P *server = TLM_DBUS_SERVER_P2P (user_data);
277 gpointer login_object = g_hash_table_lookup (
278 server->priv->login_object_adapters, connection);
280 _clear_login_object_watchers (connection, login_object, user_data);
281 DBG("p2p dbus connection(%p) closed (peer vanished : %d)"
282 " with error: %s", connection, remote_peer_vanished,
283 error ? error->message : "NONE");
285 g_signal_emit (server, signals[SIG_CLIENT_REMOVED], 0, login_object);
286 g_hash_table_remove (server->priv->login_object_adapters, connection);
291 _tlm_dbus_server_p2p_add_login_obj (
292 TlmDbusServerP2P *server,
293 GDBusConnection *connection)
295 TlmDbusLoginAdapter *login_object = NULL;
297 DBG("export interfaces on connection %p", connection);
299 login_object = tlm_dbus_login_adapter_new_with_connection (connection);
301 _add_login_object_watchers (connection, login_object, server);
302 g_signal_emit (server, signals[SIG_CLIENT_ADDED], 0, login_object);
307 GDBusServer *dbus_server,
308 GDBusConnection *connection,
311 TlmDbusServerP2P *server = TLM_DBUS_SERVER_P2P (user_data);
313 WARN ("memory corruption");
316 _tlm_dbus_server_p2p_add_login_obj (server, connection);
321 _tlm_dbus_server_p2p_start (
324 g_return_val_if_fail (TLM_IS_DBUS_SERVER_P2P (self), FALSE);
326 DBG("start P2P DBus Server");
328 TlmDbusServerP2P *server = TLM_DBUS_SERVER_P2P (self);
329 if (!server->priv->bus_server) {
331 gchar *guid = g_dbus_generate_guid ();
332 server->priv->bus_server = g_dbus_server_new_sync (
333 server->priv->address, G_DBUS_SERVER_FLAGS_NONE, guid, NULL,
337 if (!server->priv->bus_server) {
338 WARN ("Failed to start server at address '%s':%s",
339 server->priv->address, err ? err->message : "NULL");
344 g_signal_connect (server->priv->bus_server, "new-connection",
345 G_CALLBACK(_on_client_request), server);
348 if (!g_dbus_server_is_active (server->priv->bus_server)) {
349 const gchar *path = NULL;
350 g_dbus_server_start (server->priv->bus_server);
351 path = g_strstr_len(server->priv->address, -1, "unix:path=") + 10;
353 if (chown (path, server->priv->uid, -1) < 0) {
354 WARN("Unable to set ownership");
356 if (g_chmod (path, S_IRUSR | S_IWUSR) < 0) {
357 WARN("Unable to set mode '%d' for '%s'",
358 S_IRUSR|S_IWUSR, path);
362 DBG("dbus server started at : %s", server->priv->address);
368 _tlm_dbus_server_p2p_stop (
371 g_return_val_if_fail (TLM_IS_DBUS_SERVER_P2P (self), FALSE);
372 DBG ("self %p", self);
374 TlmDbusServerP2P *server = TLM_DBUS_SERVER_P2P (self);
376 if (server->priv->login_object_adapters) {
377 DBG("cleanup watchers");
378 g_hash_table_foreach (server->priv->login_object_adapters,
379 _clear_login_object_watchers, server);
380 g_hash_table_unref (server->priv->login_object_adapters);
381 server->priv->login_object_adapters = NULL;
384 if (server->priv->bus_server) {
385 DBG("stop P2P DBus Server");
386 g_signal_handlers_disconnect_by_func (server->priv->bus_server,
387 _on_client_request, server);
388 if (g_dbus_server_is_active (server->priv->bus_server))
389 g_dbus_server_stop (server->priv->bus_server);
390 g_object_unref (server->priv->bus_server);
391 server->priv->bus_server = NULL;
398 _tlm_dbus_server_p2p_get_remote_pid (
400 GDBusMethodInvocation *invocation)
402 pid_t remote_pid = 0;
403 GDBusConnection *connection = NULL;
405 struct ucred peer_cred;
406 socklen_t cred_size = sizeof(peer_cred);
408 g_return_val_if_fail (invocation && TLM_IS_DBUS_SERVER_P2P (self),
411 connection = g_dbus_method_invocation_get_connection (invocation);
412 peer_fd = g_socket_get_fd (g_socket_connection_get_socket (
413 G_SOCKET_CONNECTION (g_dbus_connection_get_stream(connection))));
414 if (peer_fd < 0 || getsockopt (peer_fd, SOL_SOCKET, SO_PEERCRED,
415 &peer_cred, &cred_size) != 0) {
416 WARN ("getsockopt() for SO_PEERCRED failed");
419 DBG ("remote p2p peer pid=%d uid=%d gid=%d", peer_cred.pid, peer_cred.uid,
422 return peer_cred.pid;
426 _tlm_dbus_server_p2p_interface_init (
427 TlmDbusServerInterface *iface)
429 iface->start = _tlm_dbus_server_p2p_start;
430 iface->stop = _tlm_dbus_server_p2p_stop;
431 iface->get_remote_pid = _tlm_dbus_server_p2p_get_remote_pid;
435 tlm_dbus_server_p2p_new (
436 const gchar *address,
439 TlmDbusServerP2P *server = TLM_DBUS_SERVER_P2P (
440 g_object_new (TLM_TYPE_DBUS_SERVER_P2P, "address", address, NULL));
442 DBG("create P2P DBus Server: %p", server);
446 server->priv->uid = uid;
448 if (g_str_has_prefix(address, "unix:path=")) {
449 const gchar *file_path = g_strstr_len (address, -1, "unix:path=") + 10;
451 if (g_file_test(file_path, G_FILE_TEST_EXISTS)) {
452 g_unlink (file_path);
454 gchar *base_path = g_path_get_dirname (file_path);
456 if (g_mkdir_with_parents (base_path,
457 S_IRUSR |S_IWUSR |S_IXUSR |S_IXGRP |S_IXOTH) == -1) {
458 gchar strerr_buf[MAX_STRERROR_LEN] = {0,};
459 WARN ("Could not create '%s', error: %s", base_path,
460 strerror_r(errno, strerr_buf, MAX_STRERROR_LEN));
461 g_object_unref (server);