[gupnp] Add a Linux context manager
- From: Zeeshan Ali Khattak <zeeshanak src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gupnp] Add a Linux context manager
- Date: Wed, 22 Jun 2011 15:52:48 +0000 (UTC)
commit bf09c0583c78b9c1bbfab0d37f1d77637bf42937
Author: Jens Georg <mail jensge org>
Date: Sat Apr 9 17:16:40 2011 +0300
Add a Linux context manager
This is based on RT Netlink sockets, see rtnetlink(7)
configure.ac | 28 ++-
libgupnp/Makefile.am | 12 +
libgupnp/gupnp-context-manager.c | 3 +
libgupnp/gupnp-linux-context-manager.c | 736 ++++++++++++++++++++++++++++++++
libgupnp/gupnp-linux-context-manager.h | 73 ++++
5 files changed, 851 insertions(+), 1 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index e27428b..69ad4a4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -44,7 +44,7 @@ PKG_CHECK_MODULES(GTHREAD, gthread-2.0)
AC_ARG_WITH([context_manager],
AS_HELP_STRING(
- [--with-context-manager=@<:@network-manager/unix@:>@],
+ [--with-context-manager=@<:@network-manager/unix/linux@:>@],
[Context Manager backend to use]),,
[with_context_manager="unix"])
@@ -54,6 +54,32 @@ AC_MSG_RESULT([${with_context_manager}])
AM_CONDITIONAL([USE_NETWORK_MANAGER],
[test "x$with_context_manager" = "xnetwork-manager"])
+USE_NETLINK=no
+if test "x$with_context_manager" = "xlinux"; then
+ dnl check for netlink (Linux)
+ AC_CHECK_HEADERS([sys/socket.h linux/rtnetlink.h],
+ [ USE_NETLINK=yes ],
+ [ USE_NETLINK=no ],
+ [ #ifdef HAVE_SYS_SOCKET_H
+ #include <sys/socket.h>
+ #endif
+ ])
+ if test "x$USE_NETLINK" = "xno"
+ then
+ AC_MSG_NOTICE([No rtnetlink found, falling back to unix context
+ manager])
+ else
+ AC_CHECK_HEADERS([linux/wireless.h], [], [],
+ [ #ifdef HAVE_SYS_SOCKET_H
+ #include <sys/socket.h>
+ #endif
+ ])
+ fi
+fi
+
+AM_CONDITIONAL(USE_NETLINK, test "x$USE_NETLINK" = "xyes")
+AC_SUBST(USE_NETLINK)
+
# glib-genmarshal
GLIB_GENMARSHAL=`pkg-config --variable=glib_genmarshal glib-2.0`
AC_SUBST(GLIB_GENMARSHAL)
diff --git a/libgupnp/Makefile.am b/libgupnp/Makefile.am
index 51bd427..0f05b3b 100644
--- a/libgupnp/Makefile.am
+++ b/libgupnp/Makefile.am
@@ -9,8 +9,18 @@ CONTEXT_MANAGER_IMPL =
CONTEXT_MANAGER_CFLAGS =
endif
+if USE_NETLINK
+NETLINK_CFLAGS = -DUSE_NETLINK
+CONTEXT_MANAGER_IMPL += \
+ gupnp-linux-context-manager.c \
+ gupnp-linux-context-manager.h
+else
+NETLINK_CFLAGS =
+endif
+
AM_CFLAGS = $(LIBGUPNP_CFLAGS) \
$(DBUS_GLIB_CFLAGS) \
+ $(NETLINK_CFLAGS) \
-I$(top_srcdir) \
$(CONTEXT_MANAGER_CFLAGS)
@@ -87,6 +97,8 @@ libgupnp_1_0_la_LIBADD = $(LIBGUPNP_LIBS) $(DBUS_GLIB_LIBS) $(LIBCONIC_LIBS)
EXTRA_DIST = gupnp-marshal.list \
gupnp-network-manager.c \
gupnp-network-manager.h \
+ gupnp-linux-context-manager.c \
+ gupnp-linux-context-manager.h \
gupnp-unix-context-manager.c \
gupnp-unix-context-manager.h
diff --git a/libgupnp/gupnp-context-manager.c b/libgupnp/gupnp-context-manager.c
index 193e8b7..3877cb6 100644
--- a/libgupnp/gupnp-context-manager.c
+++ b/libgupnp/gupnp-context-manager.c
@@ -373,6 +373,9 @@ gupnp_context_manager_new (GMainContext *main_context,
if (gupnp_network_manager_is_available (main_context))
impl_type = GUPNP_TYPE_NETWORK_MANAGER;
+#elif USE_NETLINK
+#include "gupnp-linux-context-manager.h"
+ impl_type = GUPNP_TYPE_LINUX_CONTEXT_MANAGER;
#endif
if (impl_type == G_TYPE_INVALID)
diff --git a/libgupnp/gupnp-linux-context-manager.c b/libgupnp/gupnp-linux-context-manager.c
new file mode 100644
index 0000000..4b39595
--- /dev/null
+++ b/libgupnp/gupnp-linux-context-manager.c
@@ -0,0 +1,736 @@
+/*
+ * Copyright (C) 2011 Jens Georg
+ *
+ * Author: Jens Georg <mail jensge org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:gupnp-linux-context-manager
+ * @short_description: Linux-specific implementation of #GUPnPContextManager
+ *
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#ifdef HAVE_LINUX_WIRELESS_H
+#include <linux/wireless.h>
+#endif
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <string.h>
+
+#include "gupnp-linux-context-manager.h"
+#include "gupnp-context.h"
+
+G_DEFINE_TYPE (GUPnPLinuxContextManager,
+ gupnp_linux_context_manager,
+ GUPNP_TYPE_CONTEXT_MANAGER);
+
+struct _GUPnPLinuxContextManagerPrivate {
+ int fd;
+ int nl_seq;
+ GSocket *netlink_socket;
+ GSource *netlink_socket_source;
+ GSource *bootstrap_source;
+
+ GHashTable *interfaces;
+};
+
+typedef enum {
+ /* Interface is up */
+ NETWORK_INTERFACE_UP = 1 << 0,
+
+ /* Interface doesn't support multicast or is P-t-P */
+ NETWORK_INTERFACE_IGNORE = 1 << 1,
+
+ /* Interface is down but has an address set */
+ NETWORK_INTERFACE_PRECONFIGURED = 1 << 2
+} NetworkInterfaceFlags;
+
+/* struct representing a network interface */
+struct _NetworkInterface {
+ /* Weak pointer to context manager associated with this interface */
+ GUPnPLinuxContextManager *manager;
+
+ /* Name of the interface (eth0 etc.) */
+ char *name;
+
+ /* ESSID for wireless interfaces */
+ char *essid;
+
+ /* States of the interface */
+ NetworkInterfaceFlags flags;
+
+ /* UPnP context associated with this interface */
+ GUPnPContext *context;
+};
+
+typedef struct _NetworkInterface NetworkInterface;
+
+/* Create a new network interface struct and query the device name */
+static NetworkInterface *
+network_device_new (GUPnPLinuxContextManager *manager,
+ int index)
+{
+ NetworkInterface *device;
+ struct ifreq ifr;
+ int ret;
+
+ /* Query interface name */
+ memset (&ifr, 0, sizeof (struct ifreq));
+ ifr.ifr_ifindex = index;
+ ret = ioctl (manager->priv->fd, SIOCGIFNAME, &ifr);
+
+ if (ret == -1) {
+ g_warning ("Could not get interface name for index %d",
+ index);
+
+ return NULL;
+ }
+
+ device = g_slice_new0 (NetworkInterface);
+ device->manager = manager;
+ device->name = g_strdup (ifr.ifr_name);
+
+ return device;
+}
+
+/* Try to update the ESSID of a network interface. */
+void
+network_device_update_essid (NetworkInterface *device)
+{
+ char *old_essid = device->essid;
+#ifdef HAVE_LINUX_WIRELESS_H
+ char essid[IW_ESSID_MAX_SIZE + 1];
+ struct iwreq iwr;
+ int ret;
+
+ /* Query essid */
+ memset (&iwr, 0, sizeof (struct iwreq));
+ memset (essid, 0, IW_ESSID_MAX_SIZE + 1);
+ strncpy (iwr.ifr_name, device->name, IFNAMSIZ);
+ iwr.u.essid.pointer = (caddr_t) essid;
+ iwr.u.essid.length = IW_ESSID_MAX_SIZE;
+ ret = ioctl (device->manager->priv->fd, SIOCGIWESSID, &iwr);
+
+ if ((ret == 0 && essid[0] != '\0') &&
+ (!device->essid || strcmp (device->essid, essid)))
+ device->essid = g_strdup (essid);
+ else
+ old_essid = NULL;
+#endif
+ if (old_essid)
+ g_free (old_essid);
+}
+
+static void
+network_device_create_context (NetworkInterface *device)
+{
+ GMainContext *main_context;
+ guint port;
+ GError *error = NULL;
+
+ /* We cannot create a context yet. But it may be that there will not
+ * be a RTM_NEWADDR message for this device if the IP address does not
+ * change so we mark this device as preconfigured and will create the
+ * context if the device comes up. If the address changes, we'll get a
+ * RTM_DELADDR before the next RTM_NEWADDR. */
+ if (!device->flags & NETWORK_INTERFACE_UP) {
+ device->flags |= NETWORK_INTERFACE_PRECONFIGURED;
+
+ return;
+ }
+
+ device->flags &= ~NETWORK_INTERFACE_PRECONFIGURED;
+
+ g_object_get (device->manager,
+ "main-context", &main_context,
+ "port", &port,
+ NULL);
+
+ network_device_update_essid (device);
+ device->context = g_initable_new (GUPNP_TYPE_CONTEXT,
+ NULL,
+ &error,
+ "main-context", main_context,
+ "interface", device->name,
+ "network", device->essid,
+ "port", port,
+ NULL);
+
+ if (error) {
+ g_warning ("Error creating GUPnP context: %s",
+ error->message);
+ g_error_free (error);
+
+ return;
+ }
+
+ g_signal_emit_by_name (device->manager,
+ "context-available",
+ device->context);
+}
+
+static void
+network_device_up (NetworkInterface *device)
+{
+ if (device->flags & NETWORK_INTERFACE_UP)
+ return;
+
+ device->flags |= NETWORK_INTERFACE_UP;
+
+ if (device->context)
+ g_signal_emit_by_name (device->manager,
+ "context-available",
+ device->context);
+ else if (device->flags & NETWORK_INTERFACE_PRECONFIGURED)
+ network_device_create_context (device);
+}
+
+static void
+network_device_down (NetworkInterface *device)
+{
+ if (!device->flags & NETWORK_INTERFACE_UP)
+ return;
+
+ device->flags &= ~NETWORK_INTERFACE_UP;
+
+ if (device->context)
+ g_signal_emit_by_name (device->manager,
+ "context-unavailable",
+ device->context);
+}
+
+static void
+network_device_free (NetworkInterface *device)
+{
+ if (device->name != NULL)
+ g_free (device->name);
+ if (device->essid != NULL)
+ g_free (device->essid);
+
+ if (device->context != NULL) {
+ g_signal_emit_by_name (device->manager,
+ "context-unavailable",
+ device->context);
+
+ g_object_unref (device->context);
+ }
+}
+
+
+static void query_all_network_interfaces (GUPnPLinuxContextManager *self);
+static void query_all_addresses (GUPnPLinuxContextManager *self);
+static void receive_netlink_message (GUPnPLinuxContextManager *self,
+ GError **error);
+static void create_context (GUPnPLinuxContextManager *self,
+ struct ifaddrmsg *ifa);
+static void remove_context (GUPnPLinuxContextManager *self,
+ struct ifaddrmsg *ifa);
+
+static gboolean
+on_netlink_message_available (GSocket *socket,
+ GIOCondition condition,
+ gpointer user_data)
+{
+ GUPnPLinuxContextManager *self;
+
+ self = GUPNP_LINUX_CONTEXT_MANAGER (user_data);
+
+ receive_netlink_message (self, NULL);
+
+ return TRUE;
+}
+
+#define RT_ATTR_OK(a,l) \
+ ((l > 0) && RTA_OK (a, l))
+
+static gboolean
+is_wireless_status_message (struct nlmsghdr *header)
+{
+ int rt_attr_len;
+ struct rtattr *rt_attr;
+
+ rt_attr = IFLA_RTA (NLMSG_DATA (header));
+ rt_attr_len = IFLA_PAYLOAD (header);
+ while (RT_ATTR_OK (rt_attr, rt_attr_len)) {
+ if (rt_attr->rta_type == IFLA_WIRELESS)
+ return TRUE;
+
+ rt_attr = RTA_NEXT (rt_attr, rt_attr_len);
+ }
+
+ return FALSE;
+}
+
+void
+create_context (GUPnPLinuxContextManager *self, struct ifaddrmsg *ifa)
+{
+ NetworkInterface *device;
+
+ remove_context (self, ifa);
+
+ device = g_hash_table_lookup (self->priv->interfaces,
+ GINT_TO_POINTER (ifa->ifa_index));
+ if (!device) {
+ g_warning ("Got new address for device %d but device is"
+ " not active",
+ ifa->ifa_index);
+
+ return;
+ }
+
+ /* If device isn't one we consider, silently skip address */
+ if (device->flags & NETWORK_INTERFACE_IGNORE)
+ return;
+
+ network_device_create_context (device);
+}
+
+void
+remove_context (GUPnPLinuxContextManager *self, struct ifaddrmsg *ifa)
+{
+ NetworkInterface *device;
+
+ device = g_hash_table_lookup (self->priv->interfaces,
+ GINT_TO_POINTER (ifa->ifa_index));
+
+ if (device && device->context) {
+ if (device->flags & NETWORK_INTERFACE_UP)
+ g_signal_emit_by_name (self,
+ "context-unavailable",
+ device->context);
+ g_object_unref (device->context);
+
+ device->context = NULL;
+ }
+
+ device->flags &= ~NETWORK_INTERFACE_PRECONFIGURED;
+}
+
+/* Idle-handler for initial interface and address bootstrapping.
+ *
+ * We cannot send the RTM_GETADDR message until we processed all packets of
+ * the RTM_GETLINK message. So on the first call this idle handler processes
+ * all answers of RTM_GETLINK on the second call all answers of RTM_GETADDR
+ * and on the third call it creates the regular socket source for listening on
+ * the netlink socket, detaching itself from the idle source afterwards.
+ */
+static gboolean
+on_bootstrap (GUPnPLinuxContextManager *self)
+{
+ if (self->priv->nl_seq == 0) {
+ query_all_network_interfaces (self);
+
+ return TRUE;
+ } else if (self->priv->nl_seq == 1) {
+ query_all_addresses (self);
+
+ return TRUE;
+ } else {
+ GMainContext *main_context;
+
+ self->priv->netlink_socket_source = g_socket_create_source
+ (self->priv->netlink_socket,
+ G_IO_IN | G_IO_PRI,
+ NULL);
+ g_object_get (self,
+ "main-context", &main_context,
+ NULL);
+
+ g_source_attach (self->priv->netlink_socket_source,
+ main_context);
+
+ g_source_set_callback (self->priv->netlink_socket_source,
+ (GSourceFunc)
+ on_netlink_message_available,
+ self,
+ NULL);
+ }
+
+ return FALSE;
+}
+
+struct nl_req_s {
+ struct nlmsghdr hdr;
+ struct rtgenmsg gen;
+};
+
+static void
+send_netlink_request (GUPnPLinuxContextManager *self,
+ guint netlink_message,
+ guint flags)
+{
+ struct nl_req_s req;
+ struct sockaddr_nl dest;
+ struct msghdr msg;
+ struct iovec io;
+ int fd;
+
+ memset (&req, 0, sizeof (req));
+ memset (&dest, 0, sizeof (dest));
+ memset (&msg, 0, sizeof (msg));
+
+ dest.nl_family = AF_NETLINK;
+ req.hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtgenmsg));
+ req.hdr.nlmsg_seq = self->priv->nl_seq++;
+ req.hdr.nlmsg_type = netlink_message;
+ req.hdr.nlmsg_flags = NLM_F_REQUEST | flags;
+ req.gen.rtgen_family = AF_INET;
+
+ io.iov_base = &req;
+ io.iov_len = req.hdr.nlmsg_len;
+
+ msg.msg_iov = &io;
+ msg.msg_iovlen = 1;
+ msg.msg_name = &dest;
+ msg.msg_namelen = sizeof (dest);
+
+ fd = g_socket_get_fd (self->priv->netlink_socket);
+ if (sendmsg (fd, (struct msghdr *) &msg, 0) < 0)
+ g_warning ("Could not send netlink message: %s",
+ strerror (errno));
+}
+
+static void
+query_all_network_interfaces (GUPnPLinuxContextManager *self)
+{
+ GError *error = NULL;
+
+ send_netlink_request (self, RTM_GETLINK, NLM_F_DUMP);
+ do {
+ receive_netlink_message (self, &error);
+ } while (error == NULL);
+}
+
+static void
+query_all_addresses (GUPnPLinuxContextManager *self)
+{
+ send_netlink_request (self,
+ RTM_GETADDR,
+ NLM_F_ROOT | NLM_F_MATCH | NLM_F_ACK);
+}
+
+/* Ignore non-multicast device, except loop-back and P-t-P devices */
+#define INTERFACE_IS_VALID(ifi) \
+ (((ifi)->ifi_flags & (IFF_MULTICAST | IFF_LOOPBACK)) && \
+ !((ifi)->ifi_flags & IFF_POINTOPOINT))
+
+static void
+handle_device_status_change (GUPnPLinuxContextManager *self,
+ struct ifinfomsg *ifi)
+{
+ gpointer key;
+ NetworkInterface *device;
+
+ key = GINT_TO_POINTER (ifi->ifi_index);
+ device = g_hash_table_lookup (self->priv->interfaces,
+ key);
+
+ if (device != NULL) {
+ if (ifi->ifi_flags & IFF_UP)
+ network_device_up (device);
+ else
+ network_device_down (device);
+
+ return;
+ }
+
+ device = network_device_new (self, ifi->ifi_index);
+ if (device) {
+ if (!INTERFACE_IS_VALID (ifi))
+ device->flags |= NETWORK_INTERFACE_IGNORE;
+ if (ifi->ifi_flags & IFF_UP)
+ device->flags |= NETWORK_INTERFACE_UP;
+
+ g_hash_table_insert (self->priv->interfaces,
+ key,
+ device);
+ }
+}
+
+static void
+remove_device (GUPnPLinuxContextManager *self,
+ struct ifinfomsg *ifi)
+{
+ g_hash_table_remove (self->priv->interfaces,
+ GINT_TO_POINTER (ifi->ifi_index));
+}
+
+#define NLMSG_IS_VALID(msg,len) \
+ (NLMSG_OK(msg,len) && (msg->nlmsg_type != NLMSG_DONE))
+
+static void
+receive_netlink_message (GUPnPLinuxContextManager *self, GError **error)
+{
+ static char buf[4096];
+ static const int bufsize = 4096;
+
+ int len;
+ GError *inner_error = NULL;
+ struct nlmsghdr *header = (struct nlmsghdr *) buf;
+ struct ifinfomsg *ifi;
+ struct ifaddrmsg *ifa;
+
+
+ len = g_socket_receive (self->priv->netlink_socket,
+ buf,
+ bufsize,
+ NULL,
+ &inner_error);
+ if (len == -1) {
+ if (inner_error->code != G_IO_ERROR_WOULD_BLOCK)
+ g_warning ("Error receiving netlink message: %s",
+ inner_error->message);
+ g_propagate_error (error, inner_error);
+
+ return;
+ }
+
+ for (;NLMSG_IS_VALID (header, len); header = NLMSG_NEXT (header,len)) {
+ switch (header->nlmsg_type) {
+ /* RTM_NEWADDR and RTM_DELADDR are sent on real address
+ * changes.
+ * RTM_NEWLINK is sent on varous occations:
+ * - Creation of a new device
+ * - Device goes up/down
+ * - Wireless status changes
+ * RTM_DELLINK is sent only if device is removed, like
+ * openvpn --rmtun /dev/tun0, NOT on ifconfig down. */
+ case RTM_NEWADDR:
+ ifa = NLMSG_DATA (header);
+ create_context (self, ifa);
+ break;
+ case RTM_DELADDR:
+ ifa = NLMSG_DATA (header);
+ remove_context (self, ifa);
+ break;
+ case RTM_NEWLINK:
+ ifi = NLMSG_DATA (header);
+
+ /* Check if wireless is up for chit-chat */
+ if (is_wireless_status_message (header))
+ continue;
+ handle_device_status_change (self, ifi);
+ break;
+ case RTM_DELLINK:
+ ifi = NLMSG_DATA (header);
+ remove_device (self, ifi);
+ break;
+ case NLMSG_ERROR:
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/* Create INET socket used for SIOCGIFNAME and SIOCGIWESSID ioctl
+ * calls */
+static gboolean
+create_ioctl_socket (GUPnPLinuxContextManager *self, GError **error)
+{
+ self->priv->fd = socket (AF_INET, SOCK_DGRAM, 0);
+
+ if (self->priv->fd < 0) {
+ self->priv->fd = 0;
+
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ g_io_error_from_errno (errno),
+ "Failed to setup socket for ioctl");
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Create a netlink socket, bind to it and wrap it in a GSocket */
+static gboolean
+create_netlink_socket (GUPnPLinuxContextManager *self, GError **error)
+{
+ struct sockaddr_nl sa;
+ int fd, status;
+ GSocket *sock;
+ GError *inner_error;
+
+ inner_error = NULL;
+
+ fd = socket (PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (fd == -1) {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ g_io_error_from_errno (errno),
+ "Failed to bind to netlink socket");
+ return FALSE;
+ }
+
+ memset (&sa, 0, sizeof (sa));
+ sa.nl_family = AF_NETLINK;
+ /* Listen for interface changes and IP address changes */
+ sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
+
+ status = bind (fd, (struct sockaddr *) &sa, sizeof (sa));
+ if (status == -1) {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ g_io_error_from_errno (errno),
+ "Failed to bind to netlink socket");
+ close (fd);
+
+ return FALSE;
+ }
+
+ sock = g_socket_new_from_fd (fd, &inner_error);
+ if (sock == NULL) {
+ close (fd);
+ g_propagate_prefixed_error (error,
+ inner_error,
+ "Failed to create GSocket from "
+ "netlink socket");
+
+ return FALSE;
+ }
+
+ g_socket_set_blocking (sock, FALSE);
+
+ self->priv->netlink_socket = sock;
+
+ return TRUE;
+}
+
+static void
+gupnp_linux_context_manager_init (GUPnPLinuxContextManager *self)
+{
+ self->priv =
+ G_TYPE_INSTANCE_GET_PRIVATE (self,
+ GUPNP_TYPE_LINUX_CONTEXT_MANAGER,
+ GUPnPLinuxContextManagerPrivate);
+
+ self->priv->nl_seq = 0;
+
+ self->priv->interfaces =
+ g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ (GDestroyNotify) network_device_free);
+}
+
+static void
+gupnp_linux_context_manager_constructed (GObject *object)
+{
+ GObjectClass *parent_class;
+ GUPnPLinuxContextManager *self;
+ GError *error = NULL;
+ GMainContext *main_context;
+
+ self = GUPNP_LINUX_CONTEXT_MANAGER (object);
+
+ g_object_get (self,
+ "main-context", &main_context,
+ NULL);
+
+ if (!create_ioctl_socket (self, &error))
+ goto cleanup;
+
+ if (!create_netlink_socket (self, &error))
+ goto cleanup;
+
+ self->priv->bootstrap_source =
+ g_idle_source_new ();
+ g_source_attach (self->priv->bootstrap_source,
+ main_context);
+ g_source_set_callback (self->priv->bootstrap_source,
+ (GSourceFunc) on_bootstrap,
+ self,
+ NULL);
+cleanup:
+ if (error) {
+ if (self->priv->fd > 0)
+ close (self->priv->fd);
+
+ g_warning ("Failed to setup Linux context manager: %s",
+ error->message);
+
+ g_error_free (error);
+ }
+
+ /* Chain-up */
+ parent_class = G_OBJECT_CLASS (gupnp_linux_context_manager_parent_class);
+ if (parent_class->constructed)
+ parent_class->constructed (object);
+}
+
+static void
+gupnp_linux_context_manager_dispose (GObject *object)
+{
+ GUPnPLinuxContextManager *self;
+ GObjectClass *parent_class;
+
+ self = GUPNP_LINUX_CONTEXT_MANAGER (object);
+
+ if (self->priv->bootstrap_source != NULL) {
+ g_source_destroy (self->priv->bootstrap_source);
+ g_source_unref (self->priv->bootstrap_source);
+ self->priv->bootstrap_source = NULL;
+ }
+
+ if (self->priv->netlink_socket_source != NULL) {
+ g_source_destroy (self->priv->netlink_socket_source);
+ g_source_unref (self->priv->netlink_socket_source);
+ self->priv->netlink_socket_source = NULL;
+ }
+
+ if (self->priv->netlink_socket != NULL) {
+ g_object_unref (self->priv->netlink_socket);
+ self->priv->netlink_socket = NULL;
+ }
+
+ if (self->priv->fd != 0) {
+ close (self->priv->fd);
+ self->priv->fd = 0;
+ }
+
+ if (self->priv->interfaces) {
+ g_hash_table_destroy (self->priv->interfaces);
+ self->priv->interfaces = NULL;
+ }
+
+ /* Chain-up */
+ parent_class = G_OBJECT_CLASS (gupnp_linux_context_manager_parent_class);
+ parent_class->dispose (object);
+}
+
+static void
+gupnp_linux_context_manager_class_init (GUPnPLinuxContextManagerClass *klass)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+
+ object_class->constructed = gupnp_linux_context_manager_constructed;
+ object_class->dispose = gupnp_linux_context_manager_dispose;
+
+ g_type_class_add_private (klass,
+ sizeof (GUPnPLinuxContextManagerPrivate));
+}
diff --git a/libgupnp/gupnp-linux-context-manager.h b/libgupnp/gupnp-linux-context-manager.h
new file mode 100644
index 0000000..263258b
--- /dev/null
+++ b/libgupnp/gupnp-linux-context-manager.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2011 Jens Georg.
+ *
+ * Author: Jens Georg <mail jensge org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GUPNP_LINUX_CONTEXT_MANAGER_H__
+#define __GUPNP_LINUX_CONTEXT_MANAGER_H__
+
+#include "gupnp-context-manager.h"
+
+G_BEGIN_DECLS
+
+GType
+gupnp_linux_context_manager_get_type (void) G_GNUC_CONST;
+
+#define GUPNP_TYPE_LINUX_CONTEXT_MANAGER \
+ (gupnp_linux_context_manager_get_type ())
+#define GUPNP_LINUX_CONTEXT_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ GUPNP_TYPE_LINUX_CONTEXT_MANAGER, \
+ GUPnPLinuxContextManager))
+#define GUPNP_LINUX_CONTEXT_MANAGER_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_CAST ((obj), \
+ GUPNP_TYPE_LINUX_CONTEXT_MANAGER, \
+ GUPnPLinuxContextManagerClass))
+#define GUPNP_IS_LINUX_CONTEXT_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ GUPNP_TYPE_LINUX_CONTEXT_MANAGER))
+#define GUPNP_IS_LINUX_CONTEXT_MANAGER_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE ((obj), \
+ GUPNP_TYPE_LINUX_CONTEXT_MANAGER))
+#define GUPNP_LINUX_CONTEXT_MANAGER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ GUPNP_TYPE_LINUX_CONTEXT_MANAGER, \
+ GUPnPLinuxContextManagerClass))
+
+typedef struct _GUPnPLinuxContextManagerPrivate GUPnPLinuxContextManagerPrivate;
+
+typedef struct {
+ GUPnPContextManager parent;
+
+ GUPnPLinuxContextManagerPrivate *priv;
+} GUPnPLinuxContextManager;
+
+typedef struct {
+ GUPnPContextManagerClass parent_class;
+
+ /* future padding */
+ void (* _gupnp_reserved1) (void);
+ void (* _gupnp_reserved2) (void);
+ void (* _gupnp_reserved3) (void);
+ void (* _gupnp_reserved4) (void);
+} GUPnPLinuxContextManagerClass;
+
+G_END_DECLS
+
+#endif /* __GUPNP_LINUX_CONTEXT_MANAGER_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]