⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gupnp-service.c

📁 另一 UPNP SDK 支持在UNIX/LINUX上运行。 UPnP是一种网络协议
💻 C
📖 第 1 页 / 共 4 页
字号:
                } else {                        g_warning ("Error collecting value: %s\n",                                   collect_error);                        g_free (collect_error);                }                var_name = va_arg (var_args, const char *);        }}/* Received notify response. */static voidnotify_got_response (SoupSession *session,                     SoupMessage *msg,                     gpointer     user_data){        SubscriptionData *data;        /* Cancelled? */        if (msg->status_code == SOUP_STATUS_CANCELLED)                return;        data = user_data;        /* Remove from pending messages list */        data->pending_messages = g_list_remove (data->pending_messages, msg);        if (SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {                /* Success: reset callbacks pointer */                data->callbacks = g_list_first (data->callbacks);        } else if (msg->status_code == SOUP_STATUS_PRECONDITION_FAILED) {                /* Precondition failed: Cancel subscription */                g_hash_table_remove (data->service->priv->subscriptions,                                     data->sid);        } else {                /* Other failure: Try next callback or signal failure. */                if (data->callbacks->next) {                        SoupURI *uri;                        GUPnPContext *context;                        SoupSession *session;                        /* Call next callback */                        data->callbacks = data->callbacks->next;                        uri = soup_uri_new (data->callbacks->data);                        soup_message_set_uri (msg, uri);                        soup_uri_free (uri);                        /* And re-queue */                        data->pending_messages =                                 g_list_prepend (data->pending_messages, msg);                        context = gupnp_service_info_get_context                                        (GUPNP_SERVICE_INFO (data->service));                        session = _gupnp_context_get_session (context);                        soup_session_requeue_message (session, msg);                } else {                        /* Emit 'notify-failed' signal */                        GError *error;                        error = g_error_new (GUPNP_EVENTING_ERROR,                                             GUPNP_EVENTING_ERROR_NOTIFY_FAILED,                                             msg->reason_phrase);                        g_signal_emit (data->service,                                       signals[NOTIFY_FAILED],                                       0,                                       data->callbacks,                                       error);                        g_error_free (error);                        /* Reset callbacks pointer */                        data->callbacks = g_list_first (data->callbacks);                }        }}/* Send notification @user_data to subscriber @value */static voidnotify_subscriber (gpointer key,                   gpointer value,                   gpointer user_data){        SubscriptionData *data;        const char *property_set;        char *tmp;        SoupMessage *msg;        GUPnPContext *context;        SoupSession *session;        data = value;        property_set = user_data;        /* Create message */        msg = soup_message_new (GENA_METHOD_NOTIFY, data->callbacks->data);        if (!msg) {                g_warning ("Invalid callback URL: %s",                           (char *) data->callbacks->data);                return;        }        soup_message_headers_append (msg->request_headers,                                     "NT",                                     "upnp:event");        soup_message_headers_append (msg->request_headers,                                     "NTS",                                     "upnp:propchange");        soup_message_headers_append (msg->request_headers,                                     "SID",                                     data->sid);        tmp = g_strdup_printf ("%d", data->seq);        soup_message_headers_append (msg->request_headers,                                     "SEQ",                                     tmp);        g_free (tmp);        /* Handle overflow */        if (data->seq < G_MAXINT32)                data->seq++;        else                data->seq = 1;        /* Add body */        soup_message_set_request (msg,                                  "text/xml",                                  SOUP_MEMORY_TAKE,                                  g_strdup (property_set),                                  strlen (property_set));        /* Queue */        data->pending_messages = g_list_prepend (data->pending_messages, msg);        context = gupnp_service_info_get_context                        (GUPNP_SERVICE_INFO (data->service));        session = _gupnp_context_get_session (context);        soup_session_queue_message (session,                                    msg,                                    notify_got_response,                                    data);}/* Create a property set from @queue */static char *create_property_set (GQueue *queue){        NotifyData *data;        GString *str;        /* Compose property set */        str = xml_util_new_string ();        g_string_append (str,                         "<?xml version=\"1.0\"?>"                         "<e:propertyset xmlns:e="                                "\"urn:schemas-upnp-org:event-1-0\">"                         "<e:property>");        /* Add variables */        while ((data = g_queue_pop_head (queue))) {                xml_util_start_element (str, data->variable);                gvalue_util_value_append_to_xml_string (&data->value, str);                xml_util_end_element (str, data->variable);                /* Cleanup */                notify_data_free (data);        }        g_string_append (str,                         "</e:property>"                         "</e:propertyset>");        /* Cleanup & return */        return g_string_free (str, FALSE);}/* Flush all queued notifications */static voidflush_notifications (GUPnPService *service){        char *mem;        /* Create property set */        mem = create_property_set (service->priv->notify_queue);        /* And send it off */        g_hash_table_foreach (service->priv->subscriptions,                              notify_subscriber,                              mem);        /* Cleanup */        g_free (mem);}/** * gupnp_service_notify_value * @service: A #GUPnPService * @variable: The name of the variable to notify * @value: The value of the variable * * Notifies listening clients that @variable has changed to @value. **/voidgupnp_service_notify_value (GUPnPService *service,                            const char   *variable,                            const GValue *value){        g_return_if_fail (GUPNP_IS_SERVICE (service));        g_return_if_fail (variable != NULL);        g_return_if_fail (G_IS_VALUE (value));        /* Queue */        NotifyData *data;        data = g_slice_new0 (NotifyData);        data->variable = g_strdup (variable);        g_value_init (&data->value, G_VALUE_TYPE (value));        g_value_copy (value, &data->value);        g_queue_push_tail (service->priv->notify_queue, data);        /* And flush, if not frozen */        if (!service->priv->notify_frozen)                flush_notifications (service);}/** * gupnp_service_freeze_notify * @service: A #GUPnPService * * Causes new notifications to be queued up until gupnp_service_thaw_notify() * is called. **/voidgupnp_service_freeze_notify (GUPnPService *service){        g_return_if_fail (GUPNP_IS_SERVICE (service));        service->priv->notify_frozen = TRUE;}/** * gupnp_service_thaw_notify * @service: A #GUPnPService * * Sends out any pending notifications, and stops queuing of new ones. **/voidgupnp_service_thaw_notify (GUPnPService *service){        g_return_if_fail (GUPNP_IS_SERVICE (service));        service->priv->notify_frozen = FALSE;        if (g_queue_get_length (service->priv->notify_queue) == 0)                return; /* Empty notify queue */        flush_notifications (service);}/* Convert a CamelCase string to a lowercase string with underscores */static char *strip_camel_case (char *camel_str){        char *stripped;        int i, j;        /* Keep enough space for underscores */        stripped = g_malloc (strlen (camel_str) * 2);        for (i = 0, j = 0; i <= strlen (camel_str); i++) {                /* Convert every upper case letter to lower case and unless                 * it's the first character, the last charachter, in the                 * middle of an abbreviation or there is already an underscore                 * before it, add an underscore before it */                if (g_ascii_isupper (camel_str[i])) {                        if (i != 0 &&                            camel_str[i + 1] != '\0' &&                            camel_str[i - 1] != '_' &&                            !g_ascii_isupper (camel_str[i - 1])) {                                stripped[j++] = '_';                        }                        stripped[j++] = g_ascii_tolower (camel_str[i]);                } else                        stripped[j++] = camel_str[i];        }        return stripped;}static GCallbackfind_callback_by_name (GModule    *module,                       const char *name){        GCallback callback;        char *full_name;        /* First try with 'on_' prefix */        full_name = g_strjoin ("_",                               "on",                               name,                               NULL);        if (!g_module_symbol (module,                              full_name,                              (gpointer) &callback)) {                g_free (full_name);                /* Now try with '_cb' postfix */                full_name = g_strjoin ("_",                                       name,                                       "cb",                                       NULL);                g_module_symbol (module,                                 full_name,                                 (gpointer) &callback);        }        g_free (full_name);        return callback;}/* Use the strings from @name_list as details to @signal_name, and connect * callbacks with names based on these same strings to @signal_name::string. */static voidconnect_names_to_signal_handlers (GUPnPService *service,                                  GModule      *module,                                  const GList  *name_list,                                  const char   *signal_name,                                  const char   *callback_prefix,                                  gpointer      user_data){        const GList *name_node;        for (name_node = name_list;             name_node;             name_node = name_node->next) {                GCallback callback;                char     *callback_name;                char     *signal_detail;                signal_detail = (char *) name_node->data;                callback_name = strip_camel_case (signal_detail);                if (callback_prefix) {                        char *tmp;                        tmp = g_strjoin ("_",                                         callback_prefix,                                         callback_name,                                         NULL);                        g_free (callback_name);                        callback_name = tmp;                }                callback = find_callback_by_name (module, callback_name);                g_free (callback_name);                if (callback == NULL)                        continue;                signal_detail = g_strjoin ("::",                                           signal_name,                                           signal_detail,                                           NULL);                g_signal_connect (service,                                  signal_detail,                                  callback,                                  user_data);                g_free (signal_detail);        }}/** * gupnp_service_signals_autoconnect * @service: A #GUPnPService * @user_data: the data to pass to each of the callbacks * @error: return location for a #GError, or %NULL * * A convenience function that attempts to connect all possible * #GUPnPService::action-invoked and #GUPnPService::query-variable signals to * appropriate callbacks for the service @service. It uses service introspection * and GModule's introspective features. It is very simillar to * glade_xml_signal_autoconnect() except that it attempts to guess the names of * the signal handlers on its own. * * For this function to do its magic, the application must name the callback * functions for #GUPnPService::action-invoked signals by striping the CamelCase * off the action names and either prepend "on_" or append "_cb" to them. Same * goes for #GUPnPService::query-variable signals, except that "query_" should * be prepended to the variable name. For example, callback function for * "GetSystemUpdateID" action should be either named as * "get_system_update_id_cb" or "on_get_system_update_id" and callback function * for the query of "SystemUpdateID" state variable should be named * "query_system_update_id_cb" or "on_query_system_update_id". * * Note that this function will not work correctly if GModule is not supported * on the platform or introspection is not available for service @service. * * WARNING: This function can not and therefore does not guarantee that the * resulting signal connections will be correct as it depends heavily on a * particular naming schemes described above. **/voidgupnp_service_signals_autoconnect (GUPnPService *service,                                   gpointer      user_data,                                   GError      **error){        GUPnPServiceIntrospection *introspection;        const GList               *names;        GModule                   *module;        g_return_if_fail (GUPNP_IS_SERVICE (service));        introspection = gupnp_service_info_get_introspection                                (GUPNP_SERVICE_INFO (service),                                 error);        if (!introspection)                return;        /* Get a handle on the main executable -- use this to find symbols */        module = g_module_open (NULL, 0);        if (module == NULL) {                g_error ("Failed to open module: %s", g_module_error ());                g_object_unref (introspection);                return;        }        names = gupnp_service_introspection_list_action_names (introspection);        connect_names_to_signal_handlers (service,                                          module,                                          names,                                          "action-invoked",                                          NULL,                                          user_data);        names = gupnp_service_introspection_list_state_variable_names                        (introspection);        connect_names_to_signal_handlers (service,                                          module,                                          names,                                          "query-variable",                                          "query",                                          user_data);        g_module_close (module);        g_object_unref (introspection);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -