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)
87 G_ADD_PRIVATE(TlmDbusServerP2P));
96 TlmDbusServerP2P *self = TLM_DBUS_SERVER_P2P (object);
97 switch (property_id) {
98 case IFACE_PROP_TYPE: {
102 self->priv->address = g_value_dup_string (value);
106 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
117 TlmDbusServerP2P *self = TLM_DBUS_SERVER_P2P (object);
119 switch (property_id) {
120 case IFACE_PROP_TYPE: {
121 g_value_set_uint (value, (guint)TLM_DBUS_SERVER_BUSTYPE_P2P);
125 g_value_set_string (value, g_dbus_server_get_client_address (
126 self->priv->bus_server));
130 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
135 _compare_by_pointer (
138 gpointer dead_object)
140 return value == dead_object;
144 _on_login_object_dispose (
148 TlmDbusServerP2P *server = TLM_DBUS_SERVER_P2P (data);
149 g_return_if_fail (server);
150 g_hash_table_foreach_steal (server->priv->login_object_adapters,
151 _compare_by_pointer, dead);
155 _clear_login_object_watchers (
157 gpointer login_object,
160 g_signal_handlers_disconnect_by_func (connection, _on_connection_closed,
162 g_object_weak_unref (G_OBJECT(login_object), _on_login_object_dispose,
167 _add_login_object_watchers (
169 gpointer login_object,
170 TlmDbusServerP2P *server)
172 g_signal_connect (connection, "closed", G_CALLBACK(_on_connection_closed),
174 g_object_weak_ref (G_OBJECT (login_object), _on_login_object_dispose,
176 g_hash_table_insert (server->priv->login_object_adapters, connection,
184 TlmDbusServerP2P *self = TLM_DBUS_SERVER_P2P (object);
186 _tlm_dbus_server_p2p_stop (TLM_DBUS_SERVER (self));
188 G_OBJECT_CLASS (tlm_dbus_server_p2p_parent_class)->dispose (object);
195 TlmDbusServerP2P *self = TLM_DBUS_SERVER_P2P (object);
196 if (self->priv->address) {
197 if (g_str_has_prefix (self->priv->address, "unix:path=")) {
198 const gchar *path = g_strstr_len(self->priv->address, -1,
204 g_free (self->priv->address);
205 self->priv->address = NULL;
207 G_OBJECT_CLASS (tlm_dbus_server_p2p_parent_class)->finalize (object);
211 tlm_dbus_server_p2p_class_init (
212 TlmDbusServerP2PClass *klass)
214 GObjectClass* object_class = G_OBJECT_CLASS (klass);
215 GParamSpec *address_spec = NULL;
217 object_class->get_property = _get_property;
218 object_class->set_property = _set_property;
219 object_class->dispose = _dispose;
220 object_class->finalize = _finalize;
222 g_object_class_override_property (object_class, IFACE_PROP_TYPE, "bustype");
224 address_spec = g_param_spec_string ("address", "server address",
225 "Server socket address", NULL,
226 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
227 G_PARAM_STATIC_STRINGS);
228 g_object_class_install_property (object_class, PROP_ADDRESS, address_spec);
230 signals[SIG_CLIENT_ADDED] = g_signal_new ("client-added",
231 TLM_TYPE_DBUS_SERVER_P2P,
239 TLM_TYPE_LOGIN_ADAPTER);
241 signals[SIG_CLIENT_REMOVED] = g_signal_new ("client-removed",
242 TLM_TYPE_DBUS_SERVER_P2P,
250 TLM_TYPE_LOGIN_ADAPTER);
254 tlm_dbus_server_p2p_init (
255 TlmDbusServerP2P *self)
257 self->priv = tlm_dbus_server_p2p_get_instance_private (self);
258 self->priv->bus_server = NULL;
259 self->priv->address = NULL;
261 self->priv->login_object_adapters = g_hash_table_new_full (g_direct_hash,
262 g_direct_equal, NULL, g_object_unref);
266 _on_connection_closed (
267 GDBusConnection *connection,
268 gboolean remote_peer_vanished,
272 TlmDbusServerP2P *server = TLM_DBUS_SERVER_P2P (user_data);
273 gpointer login_object = g_hash_table_lookup (
274 server->priv->login_object_adapters, connection);
276 _clear_login_object_watchers (connection, login_object, user_data);
277 DBG("p2p dbus connection(%p) closed (peer vanished : %d)"
278 " with error: %s", connection, remote_peer_vanished,
279 error ? error->message : "NONE");
281 g_signal_emit (server, signals[SIG_CLIENT_REMOVED], 0, login_object);
282 g_hash_table_remove (server->priv->login_object_adapters, connection);
287 _tlm_dbus_server_p2p_add_login_obj (
288 TlmDbusServerP2P *server,
289 GDBusConnection *connection)
291 TlmDbusLoginAdapter *login_object = NULL;
293 DBG("export interfaces on connection %p", connection);
295 login_object = tlm_dbus_login_adapter_new_with_connection (connection);
297 _add_login_object_watchers (connection, login_object, server);
298 g_signal_emit (server, signals[SIG_CLIENT_ADDED], 0, login_object);
303 GDBusServer *dbus_server,
304 GDBusConnection *connection,
307 TlmDbusServerP2P *server = TLM_DBUS_SERVER_P2P (user_data);
309 WARN ("memory corruption");
312 _tlm_dbus_server_p2p_add_login_obj (server, connection);
317 _tlm_dbus_server_p2p_start (
320 g_return_val_if_fail (TLM_IS_DBUS_SERVER_P2P (self), FALSE);
322 DBG("start P2P DBus Server");
324 TlmDbusServerP2P *server = TLM_DBUS_SERVER_P2P (self);
325 if (!server->priv->bus_server) {
327 gchar *guid = g_dbus_generate_guid ();
328 server->priv->bus_server = g_dbus_server_new_sync (
329 server->priv->address, G_DBUS_SERVER_FLAGS_NONE, guid, NULL,
333 if (!server->priv->bus_server) {
334 WARN ("Failed to start server at address '%s':%s",
335 server->priv->address, err ? err->message : "NULL");
340 g_signal_connect (server->priv->bus_server, "new-connection",
341 G_CALLBACK(_on_client_request), server);
344 if (!g_dbus_server_is_active (server->priv->bus_server)) {
345 const gchar *path = NULL;
346 g_dbus_server_start (server->priv->bus_server);
347 path = g_strstr_len(server->priv->address, -1, "unix:path=") + 10;
349 if (chown (path, server->priv->uid, -1) < 0) {
350 WARN("Unable to set ownership");
352 if (g_chmod (path, S_IRUSR | S_IWUSR) < 0) {
353 WARN("Unable to set mode '%d' for '%s'",
354 S_IRUSR|S_IWUSR, path);
358 DBG("dbus server started at : %s", server->priv->address);
364 _tlm_dbus_server_p2p_stop (
367 g_return_val_if_fail (TLM_IS_DBUS_SERVER_P2P (self), FALSE);
368 DBG ("self %p", self);
370 TlmDbusServerP2P *server = TLM_DBUS_SERVER_P2P (self);
372 if (server->priv->login_object_adapters) {
373 DBG("cleanup watchers");
374 g_hash_table_foreach (server->priv->login_object_adapters,
375 _clear_login_object_watchers, server);
376 g_hash_table_unref (server->priv->login_object_adapters);
377 server->priv->login_object_adapters = NULL;
380 if (server->priv->bus_server) {
381 DBG("stop P2P DBus Server");
382 g_signal_handlers_disconnect_by_func (server->priv->bus_server,
383 _on_client_request, server);
384 if (g_dbus_server_is_active (server->priv->bus_server))
385 g_dbus_server_stop (server->priv->bus_server);
386 g_object_unref (server->priv->bus_server);
387 server->priv->bus_server = NULL;
394 _tlm_dbus_server_p2p_get_remote_pid (
396 GDBusMethodInvocation *invocation)
398 pid_t remote_pid = 0;
399 GDBusConnection *connection = NULL;
401 struct ucred peer_cred;
402 socklen_t cred_size = sizeof(peer_cred);
404 g_return_val_if_fail (invocation && TLM_IS_DBUS_SERVER_P2P (self),
407 connection = g_dbus_method_invocation_get_connection (invocation);
408 peer_fd = g_socket_get_fd (g_socket_connection_get_socket (
409 G_SOCKET_CONNECTION (g_dbus_connection_get_stream(connection))));
410 if (peer_fd < 0 || getsockopt (peer_fd, SOL_SOCKET, SO_PEERCRED,
411 &peer_cred, &cred_size) != 0) {
412 WARN ("getsockopt() for SO_PEERCRED failed");
415 DBG ("remote p2p peer pid=%d uid=%d gid=%d", peer_cred.pid, peer_cred.uid,
418 return peer_cred.pid;
422 _tlm_dbus_server_p2p_interface_init (
423 TlmDbusServerInterface *iface)
425 iface->start = _tlm_dbus_server_p2p_start;
426 iface->stop = _tlm_dbus_server_p2p_stop;
427 iface->get_remote_pid = _tlm_dbus_server_p2p_get_remote_pid;
431 tlm_dbus_server_p2p_new (
432 const gchar *address,
435 TlmDbusServerP2P *server = TLM_DBUS_SERVER_P2P (
436 g_object_new (TLM_TYPE_DBUS_SERVER_P2P, "address", address, NULL));
438 DBG("create P2P DBus Server: %p", server);
442 server->priv->uid = uid;
444 if (g_str_has_prefix(address, "unix:path=")) {
445 const gchar *file_path = g_strstr_len (address, -1, "unix:path=") + 10;
447 if (g_file_test(file_path, G_FILE_TEST_EXISTS)) {
448 g_unlink (file_path);
450 gchar *base_path = g_path_get_dirname (file_path);
452 if (g_mkdir_with_parents (base_path,
453 S_IRUSR |S_IWUSR |S_IXUSR |S_IXGRP |S_IXOTH) == -1) {
454 gchar strerr_buf[MAX_STRERROR_LEN] = {0,};
455 WARN ("Could not create '%s', error: %s", base_path,
456 strerror_r(errno, strerr_buf, MAX_STRERROR_LEN));
457 g_object_unref (server);