📄 gupnp-service-proxy.c
字号:
g_hash_table_foreach (hash, (GHFunc) read_out_parameter, params); /* Cleanup */ gupnp_service_proxy_action_free (action); xmlFreeDoc (response); return TRUE;}/** * gupnp_service_proxy_cancel_action * @proxy: A #GUPnPServiceProxy * @action: A #GUPnPServiceProxyAction handle * * Cancels @action, freeing the @action handle. **/voidgupnp_service_proxy_cancel_action (GUPnPServiceProxy *proxy, GUPnPServiceProxyAction *action){ GUPnPContext *context; SoupSession *session; g_return_if_fail (GUPNP_IS_SERVICE_PROXY (proxy)); g_return_if_fail (action); if (action->msg != NULL) { context = gupnp_service_info_get_context (GUPNP_SERVICE_INFO (proxy)); session = _gupnp_context_get_session (context); soup_session_cancel_message (session, action->msg, SOUP_STATUS_CANCELLED); } if (action->error != NULL) g_error_free (action->error); gupnp_service_proxy_action_free (action);}/** * gupnp_service_proxy_add_notify * @proxy: A #GUPnPServiceProxy * @variable: The variable to add notification for * @type: The type of the variable * @callback: The callback to call when @variable changes * @user_data: User data for @callback * * Sets up @callback to be called whenever a change notification for * @variable is recieved. * * Return value: %TRUE on success. **/gbooleangupnp_service_proxy_add_notify (GUPnPServiceProxy *proxy, const char *variable, GType type, GUPnPServiceProxyNotifyCallback callback, gpointer user_data){ NotifyData *data; CallbackData *callback_data; g_return_val_if_fail (GUPNP_IS_SERVICE_PROXY (proxy), FALSE); g_return_val_if_fail (variable, FALSE); g_return_val_if_fail (type, FALSE); g_return_val_if_fail (callback, FALSE); /* See if we already have notifications set up for this variable */ data = g_hash_table_lookup (proxy->priv->notify_hash, variable); if (data == NULL) { /* No, create one */ data = g_slice_new (NotifyData); data->type = type; data->callbacks = NULL; g_hash_table_insert (proxy->priv->notify_hash, g_strdup (variable), data); } else { /* Yes, check that everything is sane .. */ if (data->type != type) { g_warning ("A notification already exists for %s, but " "has type %s, not %s.", variable, g_type_name (data->type), g_type_name (type)); return FALSE; } } /* Append callback */ callback_data = g_slice_new (CallbackData); callback_data->callback = callback; callback_data->user_data = user_data; data->callbacks = g_list_append (data->callbacks, callback_data); return TRUE;}/** * gupnp_service_proxy_remove_notify * @proxy: A #GUPnPServiceProxy * @variable: The variable to add notification for * @callback: The callback to call when @variable changes * @user_data: User data for @callback * * Cancels the variable change notification for @callback and @user_data. * * Return value: %TRUE on success. **/gbooleangupnp_service_proxy_remove_notify (GUPnPServiceProxy *proxy, const char *variable, GUPnPServiceProxyNotifyCallback callback, gpointer user_data){ NotifyData *data; gboolean found; GList *l; g_return_val_if_fail (GUPNP_IS_SERVICE_PROXY (proxy), FALSE); g_return_val_if_fail (variable, FALSE); g_return_val_if_fail (callback, FALSE); /* Look up NotifyData for variable */ data = g_hash_table_lookup (proxy->priv->notify_hash, variable); if (data == NULL) { g_warning ("No notifications found for variable %s", variable); return FALSE; } /* Look up our callback-user_data pair */ found = FALSE; for (l = data->callbacks; l; l = l->next) { CallbackData *callback_data; callback_data = l->data; if (callback_data->callback == callback && callback_data->user_data == user_data) { /* Gotcha! */ g_slice_free (CallbackData, callback_data); data->callbacks = g_list_delete_link (data->callbacks, l); if (data->callbacks == NULL) { /* No callbacks left: Remove from hash */ g_hash_table_remove (proxy->priv->notify_hash, data); } found = TRUE; break; } } if (found == FALSE) g_warning ("No such callback-user_data pair was found"); return found;}/* Emit pending notifications. See comment below on why we do this. */static gbooleanemit_notifications (gpointer user_data){ GUPnPServiceProxy *proxy = user_data; g_assert (user_data); while (proxy->priv->pending_notifies != NULL) { xmlDoc *doc; xmlNode *node; doc = proxy->priv->pending_notifies->data; node = xmlDocGetRootElement (doc); /* Iterate over all provided properties */ for (node = node->children; node; node = node->next) { xmlNode *var_node; if (strcmp ((char *) node->name, "property") != 0) continue; /* property */ for (var_node = node->children; var_node; var_node = var_node->next) { NotifyData *data; GValue value = {0, }; GList *l; data = g_hash_table_lookup (proxy->priv->notify_hash, var_node->name); if (data == NULL) continue; /* Make a GValue of the desired type */ g_value_init (&value, data->type); if (!gvalue_util_set_value_from_xml_node (&value, var_node)) { g_value_unset (&value); continue; } /* Call callbacks */ for (l = data->callbacks; l; l = l->next) { CallbackData *callback_data; callback_data = l->data; callback_data->callback (proxy, (const char *) var_node->name, &value, callback_data->user_data); } /* Cleanup */ g_value_unset (&value); } } /* Cleanup */ xmlFreeDoc (doc); proxy->priv->pending_notifies = g_list_delete_link (proxy->priv->pending_notifies, proxy->priv->pending_notifies); } proxy->priv->notify_idle_id = 0; return FALSE;}/* * HTTP server received a message. Handle, if this was a NOTIFY * message with our SID. */static voidserver_handler (SoupServer *soup_server, SoupMessage *msg, const char *server_path, GHashTable *query, SoupClientContext *soup_client, gpointer user_data){ GUPnPServiceProxy *proxy; const char *hdr; int seq; xmlDoc *doc; xmlNode *node; proxy = GUPNP_SERVICE_PROXY (user_data); if (strcmp (msg->method, GENA_METHOD_NOTIFY) != 0) { /* We don't implement this method */ soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED); return; } hdr = soup_message_headers_get (msg->request_headers, "NT"); if (hdr == NULL || strcmp (hdr, "upnp:event") != 0) { /* Proper NT header lacking */ soup_message_set_status (msg, SOUP_STATUS_PRECONDITION_FAILED); return; } hdr = soup_message_headers_get (msg->request_headers, "NTS"); if (hdr == NULL || strcmp (hdr, "upnp:propchange") != 0) { /* Proper NTS header lacking */ soup_message_set_status (msg, SOUP_STATUS_PRECONDITION_FAILED); return; } hdr = soup_message_headers_get (msg->request_headers, "SID"); if (hdr == NULL || (proxy->priv->sid && (strcmp (hdr, proxy->priv->sid) != 0))) { /* No SID or not ours */ soup_message_set_status (msg, SOUP_STATUS_PRECONDITION_FAILED); return; } /* We do not error out if proxy->priv->sid is NIL as the subscription * response may not have been processed yet. */#if 0 if (!proxy->priv->sid) { GUPnPContext *context; GMainContext *main_context; context = gupnp_service_info_get_context (GUPNP_SERVICE_INFO (proxy)); main_context = gssdp_client_get_main_context (GSSDP_CLIENT (context)); /* Wait. Perhaps the subscription response has not yet * been processed. */ g_main_context_iteration (main_context, FALSE); if (!proxy->priv->sid || strcmp (hdr, proxy->priv->sid) != 0) { /* Really not our SID */ soup_message_set_status (msg, SOUP_STATUS_PRECONDITION_FAILED); return; } }#endif hdr = soup_message_headers_get (msg->request_headers, "SEQ"); if (hdr == NULL) { /* No SEQ header */ soup_message_set_status (msg, SOUP_STATUS_PRECONDITION_FAILED); return; } seq = atoi (hdr); if (seq > proxy->priv->seq) { /* Oops, we missed a notify. Resubscribe .. */ unsubscribe (proxy); subscribe (proxy); /* Message was OK otherwise */ soup_message_set_status (msg, SOUP_STATUS_OK); return; } /* Increment our own event sequence number */ if (proxy->priv->seq < G_MAXINT32) proxy->priv->seq++; else proxy->priv->seq = 1; /* Parse the actual XML message content */ doc = xmlParseMemory (msg->request_body->data, msg->request_body->length); if (doc == NULL) { /* Failed */ g_warning ("Failed to parse NOTIFY message body"); soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR); return; } /* Get root propertyset element */ node = xmlDocGetRootElement (doc); if (node == NULL || strcmp ((char *) node->name, "propertyset")) { /* Empty or unsupported */ xmlFreeDoc (doc); soup_message_set_status (msg, SOUP_STATUS_OK); return; } /* * Some UPnP stacks (hello, myigd/1.0) block when sending a NOTIFY, so * call the callbacks in an idle handler so that if the client calls the * device in the notify callback the server can actually respond. */ proxy->priv->pending_notifies =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -