📄 gupnp-service-proxy.c
字号:
* parameter value, followed by %NULL, and then tuples of out paramater name, * out parameter type, and out parameter value location * * See gupnp_service_proxy_send_action(); this version takes a va_list for * use by language bindings. * * Return value: %TRUE if sending the action was succesful. **/gbooleangupnp_service_proxy_send_action_valist (GUPnPServiceProxy *proxy, const char *action, GError **error, va_list var_args){ GUPnPContext *context; GMainContext *main_context; GMainLoop *main_loop; GUPnPServiceProxyAction *handle; g_return_val_if_fail (GUPNP_IS_SERVICE_PROXY (proxy), FALSE); g_return_val_if_fail (action, FALSE); context = gupnp_service_info_get_context (GUPNP_SERVICE_INFO (proxy)); main_context = gssdp_client_get_main_context (GSSDP_CLIENT (context)); main_loop = g_main_loop_new (main_context, TRUE); handle = gupnp_service_proxy_begin_action_valist (proxy, action, stop_main_loop, main_loop, var_args); /* Loop till we get a reply (or time out) */ if (g_main_loop_is_running (main_loop)) g_main_loop_run (main_loop); g_main_loop_unref (main_loop); if (!gupnp_service_proxy_end_action_valist (proxy, handle, error, handle->var_args)) return FALSE; return TRUE;}/** * gupnp_service_proxy_send_action_hash * @proxy: A #GUPnPServiceProxy * @action: An action * @error: The location where to store any error, or %NULL * @in_hash: A #GHashTable of in parameter name and #GValue pairs * @out_hash: A #GHashTable of out parameter name and initialized * #GValue pairs * * See gupnp_service_proxy_send_action(); this version takes a pair of * #GHashTable<!-- -->s for runtime determined parameter lists. * * Return value: %TRUE if sending the action was succesful. **/gbooleangupnp_service_proxy_send_action_hash (GUPnPServiceProxy *proxy, const char *action, GError **error, GHashTable *in_hash, GHashTable *out_hash){ GUPnPContext *context; GMainContext *main_context; GMainLoop *main_loop; GUPnPServiceProxyAction *handle; g_return_val_if_fail (GUPNP_IS_SERVICE_PROXY (proxy), FALSE); g_return_val_if_fail (action, FALSE); context = gupnp_service_info_get_context (GUPNP_SERVICE_INFO (proxy)); main_context = gssdp_client_get_main_context (GSSDP_CLIENT (context)); main_loop = g_main_loop_new (main_context, TRUE); handle = gupnp_service_proxy_begin_action_hash (proxy, action, stop_main_loop, main_loop, in_hash); if (!handle) { g_main_loop_unref (main_loop); return FALSE; } /* Loop till we get a reply (or time out) */ if (g_main_loop_is_running (main_loop)) g_main_loop_run (main_loop); g_main_loop_unref (main_loop); if (!gupnp_service_proxy_end_action_hash (proxy, handle, error, out_hash)) return FALSE; return TRUE;}/** * gupnp_service_proxy_begin_action * @proxy: A #GUPnPServiceProxy * @action: An action * @callback: The callback to call when sending the action has succeeded * or failed * @user_data: User data for @callback * @Varargs: tuples of in parameter name, in paramater type, and in parameter * value, terminated with %NULL * * Sends action @action with parameters @Varargs to the service exposed by * @proxy asynchronously, calling @callback on completion. From @callback, call * gupnp_service_proxy_end_action() to check for errors, to retrieve return * values, and to free the #GUPnPServiceProxyAction. * * Return value: A #GUPnPServiceProxyAction handle. This will * be freed when calling gupnp_service_proxy_cancel_action() or * gupnp_service_proxy_end_action_valist(). **/GUPnPServiceProxyAction *gupnp_service_proxy_begin_action (GUPnPServiceProxy *proxy, const char *action, GUPnPServiceProxyActionCallback callback, gpointer user_data, ...){ va_list var_args; GUPnPServiceProxyAction *ret; va_start (var_args, user_data); ret = gupnp_service_proxy_begin_action_valist (proxy, action, callback, user_data, var_args); va_end (var_args); return ret;}/* Begins a basic action message */static GUPnPServiceProxyAction *begin_action_msg (GUPnPServiceProxy *proxy, const char *action, GUPnPServiceProxyActionCallback callback, gpointer user_data){ GUPnPServiceProxyAction *ret; char *control_url, *full_action; const char *service_type; /* Create action structure */ ret = g_slice_new (GUPnPServiceProxyAction); ret->proxy = proxy; ret->callback = callback; ret->user_data = user_data; ret->msg = NULL; ret->error = NULL; proxy->priv->pending_actions = g_list_prepend (proxy->priv->pending_actions, ret); /* Make sure we have a service type */ service_type = gupnp_service_info_get_service_type (GUPNP_SERVICE_INFO (proxy)); if (service_type == NULL) { ret->error = g_error_new (GUPNP_SERVER_ERROR, GUPNP_SERVER_ERROR_OTHER, "No service type defined"); return ret; } /* Create message */ control_url = gupnp_service_info_get_control_url (GUPNP_SERVICE_INFO (proxy)); if (control_url != NULL) { ret->msg = soup_message_new (SOUP_METHOD_POST, control_url); g_free (control_url); } if (ret->msg == NULL) { ret->error = g_error_new (GUPNP_SERVER_ERROR, GUPNP_SERVER_ERROR_INVALID_URL, "No valid control URL defined"); return ret; } /* Specify action */ full_action = g_strdup_printf ("\"%s#%s\"", service_type, action); soup_message_headers_append (ret->msg->request_headers, "SOAPAction", full_action); g_free (full_action); /* Specify user agent and language */ http_request_set_user_agent (ret->msg); http_request_set_accept_language (ret->msg); /* Set up envelope */ ret->msg_str = xml_util_new_string (); g_string_append (ret->msg_str, "<?xml version=\"1.0\"?>" "<s:Envelope xmlns:s=" "\"http://schemas.xmlsoap.org/soap/envelope/\" " "s:encodingStyle=" "\"http://schemas.xmlsoap.org/soap/encoding/\">" "<s:Body>"); g_string_append (ret->msg_str, "<u:"); g_string_append (ret->msg_str, action); g_string_append (ret->msg_str, " xmlns:u=\""); g_string_append (ret->msg_str, service_type); g_string_append (ret->msg_str, "\">"); return ret;}/* Received response to action message */static voidaction_got_response (SoupSession *session, SoupMessage *msg, GUPnPServiceProxyAction *action){ const char *full_action; switch (msg->status_code) { case SOUP_STATUS_CANCELLED: /* Silently return */ break; case SOUP_STATUS_METHOD_NOT_ALLOWED: /* Retry with M-POST */ msg->method = "M-POST"; soup_message_headers_append (msg->request_headers, "Man", "\"http://schemas.xmlsoap.org/soap/envelope/\"; ns=s"); /* Rename "SOAPAction" to "s-SOAPAction" */ full_action = soup_message_headers_get (msg->request_headers, "SOAPAction"); soup_message_headers_append (msg->request_headers, "s-SOAPAction", full_action); soup_message_headers_remove (msg->request_headers, "SOAPAction"); /* And re-queue */ soup_session_requeue_message (session, msg); break; default: /* Success: Call callback */ action->callback (action->proxy, action, action->user_data); break; }}/* Finishes an action message and sends it off */static voidfinish_action_msg (GUPnPServiceProxyAction *action, const char *action_name){ GUPnPContext *context; SoupSession *session; /* Finish message */ g_string_append (action->msg_str, "</u:"); g_string_append (action->msg_str, action_name); g_string_append_c (action->msg_str, '>'); g_string_append (action->msg_str, "</s:Body>" "</s:Envelope>"); soup_message_set_request (action->msg, "text/xml", SOUP_MEMORY_TAKE, action->msg_str->str, action->msg_str->len); g_string_free (action->msg_str, FALSE); /* We need to keep our own reference to the message as well, * in order for send_action() to work. */ g_object_ref (action->msg); /* Send the message */ context = gupnp_service_info_get_context (GUPNP_SERVICE_INFO (action->proxy)); session = _gupnp_context_get_session (context); soup_session_queue_message (session, action->msg, (SoupSessionCallback) action_got_response, action);}/* Writes a parameter name and GValue pair to @msg */static voidwrite_in_parameter (const char *arg_name, GValue *value, GString *msg_str){ /* Write parameter pair */ xml_util_start_element (msg_str, arg_name); gvalue_util_value_append_to_xml_string (value, msg_str); xml_util_end_element (msg_str, arg_name);}/** * gupnp_service_proxy_begin_action_valist * @proxy: A #GUPnPServiceProxy * @action: An action * @callback: The callback to call when sending the action has succeeded * or failed * @user_data: User data for @callback * @var_args: A va_list of tuples of in parameter name, in paramater type, and * in parameter value * * See gupnp_service_proxy_begin_action(); this version takes a va_list for * use by language bindings. * * Return value: A #GUPnPServiceProxyAction handle. This will * be freed when calling gupnp_service_proxy_cancel_action() or * gupnp_service_proxy_end_action_valist(). **/GUPnPServiceProxyAction *gupnp_service_proxy_begin_action_valist (GUPnPServiceProxy *proxy, const char *action, GUPnPServiceProxyActionCallback callback, gpointer user_data, va_list var_args){ const char *arg_name; GUPnPServiceProxyAction *ret; g_return_val_if_fail (GUPNP_IS_SERVICE_PROXY (proxy), NULL); g_return_val_if_fail (action, NULL); g_return_val_if_fail (callback, NULL); /* Create message */ ret = begin_action_msg (proxy, action, callback, user_data); if (ret->error) { callback (proxy, ret, user_data); return ret; } /* Arguments */ arg_name = va_arg (var_args, const char *); while (arg_name) { GType arg_type; GValue value = { 0, }; char *collect_error = NULL; arg_type = va_arg (var_args, GType); g_value_init (&value, arg_type); G_VALUE_COLLECT (&value, var_args, 0, &collect_error); if (!collect_error) { write_in_parameter (arg_name, &value, ret->msg_str); g_value_unset (&value);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -