📄 gupnp-service-proxy.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-service-proxy * @short_description: Proxy class for remote services. * * #GUPnPServiceProxy sends commands to a remote UPnP service and handles * incoming event notifications. #GUPnPServiceProxy implements the * #GUPnPServiceInfo interface. */#include <libsoup/soup.h>#include <gobject/gvaluecollector.h>#include <string.h>#include <locale.h>#include "gupnp-service-proxy.h"#include "gupnp-context-private.h"#include "gupnp-error.h"#include "gupnp-error-private.h"#include "gupnp-types.h"#include "xml-util.h"#include "gena-protocol.h"#include "http-headers.h"#include "gvalue-util.h"G_DEFINE_TYPE (GUPnPServiceProxy, gupnp_service_proxy, GUPNP_TYPE_SERVICE_INFO);struct _GUPnPServiceProxyPrivate { gboolean subscribed; GList *pending_actions; char *path; /* Path to this proxy */ char *sid; /* Subscription ID */ guint subscription_timeout_id; int seq; /* Event sequence number */ GHashTable *notify_hash; GList *pending_messages; /* Pending SoupMessages from this proxy */ GList *pending_notifies; /* Pending notifications to be sent (xmlDoc*) */ guint notify_idle_id; /* Idle handler ID of notification emiter */};enum { PROP_0, PROP_SUBSCRIBED};enum { SUBSCRIPTION_LOST, LAST_SIGNAL};static guint signals[LAST_SIGNAL];struct _GUPnPServiceProxyAction { GUPnPServiceProxy *proxy; SoupMessage *msg; GString *msg_str; GUPnPServiceProxyActionCallback callback; gpointer user_data; GError *error; /* If non-NULL, description of error that occurred when preparing message */ va_list var_args; /* The va_list after begin_action_valist has gone through it. Used by send_action_valist(). */};typedef struct { GType type; GList *callbacks;} NotifyData;typedef struct { GUPnPServiceProxyNotifyCallback callback; gpointer user_data;} CallbackData;static voidsubscribe_got_response (SoupSession *session, SoupMessage *msg, GUPnPServiceProxy *proxy);static voidsubscribe (GUPnPServiceProxy *proxy);static voidunsubscribe (GUPnPServiceProxy *proxy);static voidgupnp_service_proxy_action_free (GUPnPServiceProxyAction *action){ action->proxy->priv->pending_actions = g_list_remove (action->proxy->priv->pending_actions, action); if (action->msg != NULL) g_object_unref (action->msg); g_slice_free (GUPnPServiceProxyAction, action);}static voidnotify_data_free (NotifyData *data){ g_list_free (data->callbacks); g_slice_free (NotifyData, data);}static voidgupnp_service_proxy_init (GUPnPServiceProxy *proxy){ static int proxy_counter = 0; proxy->priv = G_TYPE_INSTANCE_GET_PRIVATE (proxy, GUPNP_TYPE_SERVICE_PROXY, GUPnPServiceProxyPrivate); /* Generate unique path */ proxy->priv->path = g_strdup_printf ("/ServiceProxy%d", proxy_counter); proxy_counter++; /* Set up notify hash */ proxy->priv->notify_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) notify_data_free);}static voidgupnp_service_proxy_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec){ GUPnPServiceProxy *proxy; proxy = GUPNP_SERVICE_PROXY (object); switch (property_id) { case PROP_SUBSCRIBED: gupnp_service_proxy_set_subscribed (proxy, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; }}static voidgupnp_service_proxy_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec){ GUPnPServiceProxy *proxy; proxy = GUPNP_SERVICE_PROXY (object); switch (property_id) { case PROP_SUBSCRIBED: g_value_set_boolean (value, proxy->priv->subscribed); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; }}static voidgupnp_service_proxy_dispose (GObject *object){ GUPnPServiceProxy *proxy; GObjectClass *object_class; GUPnPContext *context; SoupSession *session; proxy = GUPNP_SERVICE_PROXY (object); /* Unsubscribe */ if (proxy->priv->subscribed) { unsubscribe (proxy); proxy->priv->subscribed = FALSE; } /* Cancel pending actions */ while (proxy->priv->pending_actions) { GUPnPServiceProxyAction *action; action = proxy->priv->pending_actions->data; gupnp_service_proxy_cancel_action (proxy, action); } /* Cancel pending messages */ context = gupnp_service_info_get_context (GUPNP_SERVICE_INFO (proxy)); if (context) session = _gupnp_context_get_session (context); else session = NULL; /* Not the first time dispose is called. */ while (proxy->priv->pending_messages) { SoupMessage *msg; msg = proxy->priv->pending_messages->data; soup_session_cancel_message (session, msg, SOUP_STATUS_CANCELLED); proxy->priv->pending_messages = g_list_delete_link (proxy->priv->pending_messages, proxy->priv->pending_messages); } /* Cancel pending notifications */ if (proxy->priv->notify_idle_id) { g_source_remove (proxy->priv->notify_idle_id); proxy->priv->notify_idle_id = 0; } while (proxy->priv->pending_notifies) { xmlFreeDoc (proxy->priv->pending_notifies->data); proxy->priv->pending_notifies = g_list_delete_link (proxy->priv->pending_notifies, proxy->priv->pending_notifies); } /* Call super */ object_class = G_OBJECT_CLASS (gupnp_service_proxy_parent_class); object_class->dispose (object);}static voidgupnp_service_proxy_finalize (GObject *object){ GUPnPServiceProxy *proxy; GObjectClass *object_class; proxy = GUPNP_SERVICE_PROXY (object); g_free (proxy->priv->path); g_hash_table_destroy (proxy->priv->notify_hash); /* Call super */ object_class = G_OBJECT_CLASS (gupnp_service_proxy_parent_class); object_class->finalize (object);}static voidgupnp_service_proxy_class_init (GUPnPServiceProxyClass *klass){ GObjectClass *object_class; object_class = G_OBJECT_CLASS (klass); object_class->set_property = gupnp_service_proxy_set_property; object_class->get_property = gupnp_service_proxy_get_property; object_class->dispose = gupnp_service_proxy_dispose; object_class->finalize = gupnp_service_proxy_finalize; g_type_class_add_private (klass, sizeof (GUPnPServiceProxyPrivate)); /** * GUPnPServiceProxy:subscribed * * Whether we are subscribed to this service. **/ g_object_class_install_property (object_class, PROP_SUBSCRIBED, g_param_spec_boolean ("subscribed", "Subscribed", "Whether we are subscribed to this " "service", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); /** * GUPnPServiceProxy::subscription-lost * @proxy: The #GUPnPServiceProxy that received the signal * @error: A pointer to a #GError describing why the subscription has * been lost * * Emitted whenever the subscription to this service has been lost due * to an error condition. **/ signals[SUBSCRIPTION_LOST] = g_signal_new ("subscription-lost", GUPNP_TYPE_SERVICE_PROXY, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GUPnPServiceProxyClass, subscription_lost), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);}/** * gupnp_service_proxy_send_action * @proxy: A #GUPnPServiceProxy * @action: An action * @error: The location where to store any error, or %NULL * @Varargs: tuples of in parameter name, in paramater type, and in parameter * value, followed by %NULL, and then tuples of out paramater name, * out parameter type, and out parameter value location, terminated with %NULL * * Sends action @action with parameters @Varargs to the service exposed by * @proxy synchronously. If an error occurred, @error will be set. In case of * a UPnPError the error code will be the same in @error. * * Return value: %TRUE if sending the action was succesful. **/gbooleangupnp_service_proxy_send_action (GUPnPServiceProxy *proxy, const char *action, GError **error, ...){ va_list var_args; gboolean ret; va_start (var_args, error); ret = gupnp_service_proxy_send_action_valist (proxy, action, error, var_args); va_end (var_args); return ret;}static voidstop_main_loop (GUPnPServiceProxy *proxy, GUPnPServiceProxyAction *action, gpointer user_data){ g_main_loop_quit ((GMainLoop *) user_data);}/** * gupnp_service_proxy_send_action_valist * @proxy: A #GUPnPServiceProxy * @action: An action * @error: The location where to store any error, or %NULL * @var_args: va_list of tuples of in parameter name, in paramater type, and in
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -