📄 gupnp-service.c
字号:
/* Unsubscription request */static voidunsubscribe (GUPnPService *service, SoupMessage *msg, const char *sid){ if (g_hash_table_remove (service->priv->subscriptions, sid)) soup_message_set_status (msg, SOUP_STATUS_OK); else soup_message_set_status (msg, SOUP_STATUS_PRECONDITION_FAILED);}/* eventSubscriptionURL handler */static voidsubscription_server_handler (SoupServer *soup_server, SoupMessage *msg, const char *server_path, GHashTable *query, SoupClientContext *soup_client, gpointer user_data){ GUPnPService *service; const char *callback, *nt, *timeout, *sid; service = GUPNP_SERVICE (user_data); callback = soup_message_headers_get (msg->request_headers, "Callback"); nt = soup_message_headers_get (msg->request_headers, "NT"); timeout = soup_message_headers_get (msg->request_headers, "Timeout"); sid = soup_message_headers_get (msg->request_headers, "SID"); /* Choose appropriate handler */ if (strcmp (msg->method, GENA_METHOD_SUBSCRIBE) == 0) { if (callback) { if (sid) { soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST); } else if (!nt || strcmp (nt, "upnp:event") != 0) { soup_message_set_status (msg, SOUP_STATUS_PRECONDITION_FAILED); } else { subscribe (service, msg, callback, timeout); } } else if (sid) { if (nt) { soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST); } else { resubscribe (service, msg, sid, timeout); } } else { soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST); } } else if (strcmp (msg->method, GENA_METHOD_UNSUBSCRIBE) == 0) { if (sid) { if (nt || callback) { soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST); } else { unsubscribe (service, msg, sid); } } else { soup_message_set_status (msg, SOUP_STATUS_PRECONDITION_FAILED); } } else { soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED); }}static GObject *gupnp_service_constructor (GType type, guint n_construct_params, GObjectConstructParam *construct_params){ GObjectClass *object_class; GObject *object; GUPnPService *service; GUPnPServiceInfo *info; GError *error; GUPnPServiceIntrospection *introspection; const GList *state_variables, *l; GUPnPContext *context; SoupServer *server; SoupURI *uri; char *url; object_class = G_OBJECT_CLASS (gupnp_service_parent_class); /* Construct */ object = object_class->constructor (type, n_construct_params, construct_params); service = GUPNP_SERVICE (object); info = GUPNP_SERVICE_INFO (object); /* Get introspection and save state variable names */ error = NULL; introspection = gupnp_service_info_get_introspection (info, &error); if (introspection) { state_variables = gupnp_service_introspection_list_state_variables (introspection); for (l = state_variables; l; l = l->next) { GUPnPServiceStateVariableInfo *variable; variable = l->data; if (!variable->send_events) continue; service->priv->state_variables = g_list_prepend (service->priv->state_variables, g_strdup (variable->name)); } g_object_unref (introspection); } else { g_warning ("Failed to get SCPD: %s\n" "The initial event message will not be sent.", error->message); g_error_free (error); } /* Get server */ context = gupnp_service_info_get_context (info); server = gupnp_context_get_server (context); /* Run listener on controlURL */ url = gupnp_service_info_get_control_url (info); uri = soup_uri_new (url); g_free (url); url = soup_uri_to_string (uri, TRUE); soup_uri_free (uri); soup_server_add_handler (server, url, control_server_handler, object, NULL); g_free (url); /* Run listener on eventSubscriptionURL */ url = gupnp_service_info_get_event_subscription_url (info); uri = soup_uri_new (url); g_free (url); url = soup_uri_to_string (uri, TRUE); soup_uri_free (uri); soup_server_add_handler (server, url, subscription_server_handler, object, NULL); g_free (url); return object;}static gbooleansay_yes (gpointer key, gpointer value, gpointer user_data){ return TRUE;}/* Root device availability changed. */static voidnotify_available_cb (GObject *object, GParamSpec *pspec, gpointer user_data){ GUPnPService *service; service = GUPNP_SERVICE (user_data); if (!gupnp_root_device_get_available (GUPNP_ROOT_DEVICE (object))) { /* Root device now unavailable: Purge subscriptions */ g_hash_table_foreach_remove (service->priv->subscriptions, say_yes, NULL); }}static voidgupnp_service_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec){ GUPnPService *service; service = GUPNP_SERVICE (object); switch (property_id) { case PROP_ROOT_DEVICE: service->priv->root_device = g_object_ref (g_value_get_object (value)); service->priv->notify_available_id = g_signal_connect_object (service->priv->root_device, "notify::available", G_CALLBACK (notify_available_cb), object, 0); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; }}static voidgupnp_service_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec){ GUPnPService *service; service = GUPNP_SERVICE (object); switch (property_id) { case PROP_ROOT_DEVICE: g_value_set_object (value, service->priv->root_device); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; }}static voidgupnp_service_dispose (GObject *object){ GUPnPService *service; GObjectClass *object_class; service = GUPNP_SERVICE (object); if (service->priv->root_device) { if (g_signal_handler_is_connected (service->priv->root_device, service->priv->notify_available_id)) { g_signal_handler_disconnect (service->priv->root_device, service->priv->notify_available_id); } g_object_unref (service->priv->root_device); service->priv->root_device = NULL; } /* Cancel pending messages */ g_hash_table_remove_all (service->priv->subscriptions); /* Call super */ object_class = G_OBJECT_CLASS (gupnp_service_parent_class); object_class->dispose (object);}static voidgupnp_service_finalize (GObject *object){ GUPnPService *service; GObjectClass *object_class; NotifyData *data; service = GUPNP_SERVICE (object); /* Free subscription hash */ g_hash_table_destroy (service->priv->subscriptions); /* Free state variable list */ while (service->priv->state_variables) { g_free (service->priv->state_variables->data); service->priv->state_variables = g_list_delete_link (service->priv->state_variables, service->priv->state_variables); } /* Free notify queue */ while ((data = g_queue_pop_head (service->priv->notify_queue))) notify_data_free (data); g_queue_free (service->priv->notify_queue); /* Call super */ object_class = G_OBJECT_CLASS (gupnp_service_parent_class); object_class->finalize (object);}static voidgupnp_service_class_init (GUPnPServiceClass *klass){ GObjectClass *object_class; GUPnPServiceInfoClass *info_class; object_class = G_OBJECT_CLASS (klass); object_class->set_property = gupnp_service_set_property; object_class->get_property = gupnp_service_get_property; object_class->constructor = gupnp_service_constructor; object_class->dispose = gupnp_service_dispose; object_class->finalize = gupnp_service_finalize; info_class = GUPNP_SERVICE_INFO_CLASS (klass); g_type_class_add_private (klass, sizeof (GUPnPServicePrivate)); /** * GUPnPService:root-device * * The containing #GUPnPRootDevice. **/ g_object_class_install_property (object_class, PROP_ROOT_DEVICE, g_param_spec_object ("root-device", "Root device", "The GUPnPRootDevice", GUPNP_TYPE_ROOT_DEVICE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); /** * GUPnPService::action-invoked * @service: The #GUPnPService that received the signal * @action: The invoked #GUPnPAction * * Emitted whenever an action is invoked. Handler should process * @action. **/ signals[ACTION_INVOKED] = g_signal_new ("action-invoked", GUPNP_TYPE_SERVICE, G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, G_STRUCT_OFFSET (GUPnPServiceClass, action_invoked), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, GUPNP_TYPE_SERVICE_ACTION); /** * GUPnPService::query-variable * @service: The #GUPnPService that received the signal * @variable: The variable that is being queried * @value: The location of the #GValue of the variable * * Emitted whenever @service needs to know the value of @variable. * Handler should fill @value with the value of @variable. **/ signals[QUERY_VARIABLE] = g_signal_new ("query-variable", GUPNP_TYPE_SERVICE, G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, G_STRUCT_OFFSET (GUPnPServiceClass, query_variable), NULL, NULL, gupnp_marshal_VOID__STRING_POINTER, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_POINTER /* Not G_TYPE_VALUE as this is an outward argument! */); /** * GUPnPService::notify-failed * @service: The #GUPnPService that received the signal * @callback_url: The callback URL * @reason: A pointer to a #GError describing why the notify failed * * Emitted whenever notification of a client fails. **/ signals[NOTIFY_FAILED] = g_signal_new ("notify-failed", GUPNP_TYPE_SERVICE, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GUPnPServiceClass, notify_failed), NULL, NULL, gupnp_marshal_VOID__POINTER_POINTER, G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);}/** * gupnp_service_notify * @service: A #GUPnPService * @Varargs: Tuples of variable name, variable type, and variable value, * terminated with %NULL. * * Notifies listening clients that the properties listed in @Varargs * have changed to the specified values. **/voidgupnp_service_notify (GUPnPService *service, ...){ va_list var_args; g_return_if_fail (GUPNP_IS_SERVICE (service)); va_start (var_args, service); gupnp_service_notify_valist (service, var_args); va_end (var_args);}/** * gupnp_service_notify_valist * @service: A #GUPnPService * @var_args: A va_list of tuples of variable name, variable type, and variable * value, terminated with %NULL. * * See gupnp_service_notify(); this version takes a va_list for * use by language bindings. **/voidgupnp_service_notify_valist (GUPnPService *service, va_list var_args){ const char *var_name; GType var_type; GValue value = {0, }; char *collect_error; g_return_if_fail (GUPNP_IS_SERVICE (service)); collect_error = NULL; var_name = va_arg (var_args, const char *); while (var_name) { var_type = va_arg (var_args, GType); g_value_init (&value, var_type); G_VALUE_COLLECT (&value, var_args, 0, &collect_error); if (!collect_error) { gupnp_service_notify_value (service, var_name, &value); g_value_unset (&value);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -