📄 gupnp-control-point.c
字号:
/* * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd. * * Author: Jorn Baayen <jorn@openedhand.com> * * 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-control-point * @short_description: Class for resource discovery. * * #GUPnPControlPoint handles device and service discovery. After creating * a control point and activating it using gssdp_resource_browser_set_active(), * the ::device-proxy-available, ::service-proxy-available, * ::device-proxy-unavailable and ::service-proxy-unavailable signals will * be emitted whenever the availability of a device or service matching * the specified discovery target changes. */#include <string.h>#include "gupnp-control-point.h"#include "gupnp-context-private.h"#include "gupnp-resource-factory-private.h"#include "http-headers.h"#include "xml-util.h"G_DEFINE_TYPE (GUPnPControlPoint, gupnp_control_point, GSSDP_TYPE_RESOURCE_BROWSER);struct _GUPnPControlPointPrivate { GUPnPResourceFactory *factory; GList *devices; GList *services; GHashTable *doc_cache; GList *pending_gets;};enum { PROP_0, PROP_RESOURCE_FACTORY,};enum { DEVICE_PROXY_AVAILABLE, DEVICE_PROXY_UNAVAILABLE, SERVICE_PROXY_AVAILABLE, SERVICE_PROXY_UNAVAILABLE, SIGNAL_LAST};static guint signals[SIGNAL_LAST];typedef struct { GUPnPControlPoint *control_point; char *udn; char *service_type; char *description_url; SoupMessage *message;} GetDescriptionURLData;static voidget_description_url_data_free (GetDescriptionURLData *data){ data->control_point->priv->pending_gets = g_list_remove (data->control_point->priv->pending_gets, data); g_free (data->udn); g_free (data->service_type); g_free (data->description_url); g_slice_free (GetDescriptionURLData, data);}static voidgupnp_control_point_init (GUPnPControlPoint *control_point){ control_point->priv = G_TYPE_INSTANCE_GET_PRIVATE (control_point, GUPNP_TYPE_CONTROL_POINT, GUPnPControlPointPrivate); control_point->priv->doc_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);}/* Return TRUE if value == user_data */static gbooleanfind_doc (gpointer key, gpointer value, gpointer user_data){ return (value == user_data);}/* xmlDoc wrapper finalized */static voiddoc_finalized (gpointer user_data, GObject *where_the_object_was){ GUPnPControlPoint *control_point; control_point = GUPNP_CONTROL_POINT (user_data); g_hash_table_foreach_remove (control_point->priv->doc_cache, find_doc, where_the_object_was);}/* Release weak reference on xmlDoc wrapper */static voidweak_unref_doc (gpointer key, gpointer value, gpointer user_data){ g_object_weak_unref (G_OBJECT (value), doc_finalized, user_data);}static voidgupnp_control_point_dispose (GObject *object){ GUPnPControlPoint *control_point; GObjectClass *object_class; control_point = GUPNP_CONTROL_POINT (object); if (control_point->priv->factory) { g_object_unref (control_point->priv->factory); control_point->priv->factory = NULL; } while (control_point->priv->devices) { g_object_unref (control_point->priv->devices->data); control_point->priv->devices = g_list_delete_link (control_point->priv->devices, control_point->priv->devices); } while (control_point->priv->services) { g_object_unref (control_point->priv->services->data); control_point->priv->services = g_list_delete_link (control_point->priv->services, control_point->priv->services); } /* Cancel any pending description file GETs */ while (control_point->priv->pending_gets) { GetDescriptionURLData *data; GUPnPContext *context; SoupSession *session; data = control_point->priv->pending_gets->data; context = gupnp_control_point_get_context (control_point); session = _gupnp_context_get_session (context); soup_session_cancel_message (session, data->message, SOUP_STATUS_CANCELLED); get_description_url_data_free (data); } /* Release weak references on remaining cached documents */ g_hash_table_foreach (control_point->priv->doc_cache, weak_unref_doc, control_point); /* Call super */ object_class = G_OBJECT_CLASS (gupnp_control_point_parent_class); object_class->dispose (object);}static voidgupnp_control_point_finalize (GObject *object){ GUPnPControlPoint *control_point; GObjectClass *object_class; control_point = GUPNP_CONTROL_POINT (object); g_hash_table_destroy (control_point->priv->doc_cache); /* Call super */ object_class = G_OBJECT_CLASS (gupnp_control_point_parent_class); object_class->finalize (object);}/* Search @element for matching services */static voidprocess_service_list (xmlNode *element, GUPnPControlPoint *control_point, XmlDocWrapper *doc, const char *udn, const char *service_type, const char *description_url, SoupURI *url_base){ for (element = element->children; element; element = element->next) { xmlChar *prop; gboolean match; GUPnPContext *context; GUPnPServiceProxy *proxy; if (strcmp ((char *) element->name, "service") != 0) continue; /* See if this is a matching service */ prop = xml_util_get_child_element_content (element, "serviceType"); if (!prop) continue; match = (strcmp ((char *) prop, service_type) == 0); xmlFree (prop); if (!match) continue; /* Match */ /* Get context */ context = gupnp_control_point_get_context (control_point); /* Create proxy */ proxy = gupnp_resource_factory_create_service_proxy (control_point->priv->factory, context, doc, element, udn, service_type, description_url, url_base); control_point->priv->services = g_list_prepend (control_point->priv->services, proxy); g_signal_emit (control_point, signals[SERVICE_PROXY_AVAILABLE], 0, proxy); }}/* Recursively search @element for matching devices */static voidprocess_device_list (xmlNode *element, GUPnPControlPoint *control_point, XmlDocWrapper *doc, const char *udn, const char *service_type, const char *description_url, SoupURI *url_base){ for (element = element->children; element; element = element->next) { xmlNode *children; xmlChar *prop; gboolean match; GUPnPContext *context; if (strcmp ((char *) element->name, "device") != 0) continue; /* Recurse into children */ children = xml_util_get_element (element, "deviceList", NULL); if (children) { process_device_list (children, control_point, doc, udn, service_type, description_url, url_base); } /* See if this is a matching device */ prop = xml_util_get_child_element_content (element, "UDN"); if (!prop) continue; match = (strcmp ((char *) prop, udn) == 0); xmlFree (prop); if (!match) continue; /* Match */ /* Get context */ context = gupnp_control_point_get_context (control_point); if (service_type) { /* Dive into serviceList */ children = xml_util_get_element (element, "serviceList", NULL); if (children) { process_service_list (children, control_point, doc, udn, service_type, description_url, url_base); } } else { /* Create device proxy */ GUPnPDeviceProxy *proxy; proxy = gupnp_resource_factory_create_device_proxy (control_point->priv->factory, context,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -