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

📄 gupnp-service.c

📁 另一 UPNP SDK 支持在UNIX/LINUX上运行。 UPnP是一种网络协议
💻 C
📖 第 1 页 / 共 4 页
字号:
        g_string_append (action->response_str, "s:Client");        xml_util_end_element (action->response_str, "faultcode");        xml_util_start_element (action->response_str, "faultstring");        g_string_append (action->response_str, "UPnPError");        xml_util_end_element (action->response_str, "faultstring");        xml_util_start_element (action->response_str, "detail");        xml_util_start_element (action->response_str,                                "UPnPError "                                "xmlns=\"urn:schemas-upnp-org:control-1-0\"");        xml_util_start_element (action->response_str, "errorCode");        g_string_append_printf (action->response_str, "%u", error_code);        xml_util_end_element (action->response_str, "errorCode");        xml_util_start_element (action->response_str, "errorDescription");        xml_util_add_content (action->response_str, error_description);        xml_util_end_element (action->response_str, "errorDescription");        xml_util_end_element (action->response_str, "UPnPError");        xml_util_end_element (action->response_str, "detail");        xml_util_end_element (action->response_str, "s:Fault");        soup_message_set_status (action->msg,                                 SOUP_STATUS_INTERNAL_SERVER_ERROR);}static voidgupnp_service_init (GUPnPService *device){        device->priv = G_TYPE_INSTANCE_GET_PRIVATE (device,                                                    GUPNP_TYPE_SERVICE,                                                    GUPnPServicePrivate);        device->priv->subscriptions =                g_hash_table_new_full (g_str_hash,                                       g_str_equal,                                       NULL,                                       (GDestroyNotify) subscription_data_free);        device->priv->notify_queue = g_queue_new ();}/* Generate a new action response node for @action_name */static GString *new_action_response_str (GUPnPService *service,                         const char   *action_name){        GString *str;        const char *type;        str = xml_util_new_string ();        g_string_append (str, "<u:");        g_string_append (str, action_name);        g_string_append (str, "Response xmlns:u=");        type = gupnp_service_info_get_service_type                                        (GUPNP_SERVICE_INFO (service));        if (type != NULL) {                g_string_append_c (str, '"');                g_string_append (str, type);                g_string_append_c (str, '"');        } else {                g_warning ("No serviceType defined. Control may not work "                           "correctly.");        }        g_string_append_c (str, '>');        return str;}/* Handle QueryStateVariable action */static voidquery_state_variable (GUPnPService       *service,                      GUPnPServiceAction *action){        xmlNode *node;        /* Iterate requested variables */        for (node = action->node->children; node; node = node->next) {                xmlChar *var_name;                GValue value = {0,};                if (strcmp ((char *) node->name, "varName") != 0)                        continue;                /* varName */                var_name = xmlNodeGetContent (node);                if (!var_name) {                        gupnp_service_action_return_error (action,                                                           402,                                                           "Invalid Args");                        return;                }                /* Query variable */                g_signal_emit (service,                               signals[QUERY_VARIABLE],                               g_quark_from_string ((char *) var_name),                               (char *) var_name,                               &value);                if (!G_IS_VALUE (&value)) {                        gupnp_service_action_return_error (action,                                                           402,                                                           "Invalid Args");                        xmlFree (var_name);                        return;                }                /* Add variable to response */                gupnp_service_action_set_value (action,                                                (char *) var_name,                                                &value);                /* Cleanup */                g_value_unset (&value);                xmlFree (var_name);        }        gupnp_service_action_return (action);}/* controlURL handler */static voidcontrol_server_handler (SoupServer        *soup_server,                        SoupMessage       *msg,                         const char        *server_path,                        GHashTable        *query,                        SoupClientContext *soup_client,                        gpointer           user_data){        GUPnPService *service;        GUPnPContext *context;        GSSDPClient *client;        xmlDoc *doc;        xmlNode *action_node;        const char *soap_action, *action_name;        char *end;        gpointer response_body;        GUPnPServiceAction *action;        service = GUPNP_SERVICE (user_data);        if (msg->method != SOUP_METHOD_POST) {                soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);                return;        }        context = gupnp_service_info_get_context (GUPNP_SERVICE_INFO (service));        client = GSSDP_CLIENT (context);        /* Get action name */        soap_action = soup_message_headers_get (msg->request_headers,                                                "SOAPAction");        action_name = strchr (soap_action, '#');        if (!action_name) {                soup_message_set_status (msg, SOUP_STATUS_PRECONDITION_FAILED);                return;        }        action_name += 1;        /* This memory is libsoup-owned so we can do this */        end = strrchr (action_name, '"');        *end = '\0';        /* Parse action_node */        doc = xmlParseMemory (msg->request_body->data,                              msg->request_body->length);        action_node = xml_util_get_element ((xmlNode *) doc,                                            "Envelope",                                            "Body",                                            action_name,                                            NULL);        if (!action_node) {                soup_message_set_status (msg, SOUP_STATUS_PRECONDITION_FAILED);                return;        }        /* Create action structure */        action = g_slice_new (GUPnPServiceAction);        action->name         = action_name;        action->msg          = msg;        action->node         = action_node;        action->response_str = new_action_response_str (service, action_name);        /* QueryStateVariable? */        if (strcmp (action_name, "QueryStateVariable") == 0)                query_state_variable (service, action);        else {                /* Emit signal. Handler parses request and fills in response. */                g_signal_emit (service,                               signals[ACTION_INVOKED],                               g_quark_from_string (action_name),                               action);                /* Was it handled? */                if (msg->status_code == SOUP_STATUS_NONE) {                        /* No. */                        gupnp_service_action_return_error (action,                                                           401,                                                           "Invalid Action");                }        }        /* Embed action->response_str in a SOAP document */        g_string_prepend (action->response_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>");        if (action->msg->status_code != SOUP_STATUS_INTERNAL_SERVER_ERROR) {                g_string_append (action->response_str, "</u:");                g_string_append (action->response_str, action_name);                g_string_append (action->response_str, "Response>");        }        g_string_append (action->response_str,                         "</s:Body>"                         "</s:Envelope>");        response_body = g_string_free (action->response_str, FALSE);        soup_message_set_response (msg,                                   "text/xml",                                   SOUP_MEMORY_TAKE,                                   response_body,                                   strlen (response_body));        /* Cleanup */        g_slice_free (GUPnPServiceAction, action);        /* Server header on response */        soup_message_headers_append (msg->response_headers,                                     "Server",                                     gssdp_client_get_server_id (client));}/* Generates a standard (re)subscription response */static voidsubscription_response (GUPnPService *service,                       SoupMessage  *msg,                       const char   *sid,                       int           timeout){        GUPnPContext *context;        GSSDPClient *client;        char *tmp;        context = gupnp_service_info_get_context (GUPNP_SERVICE_INFO (service));        client = GSSDP_CLIENT (context);        /* Server header on response */        soup_message_headers_append (msg->response_headers,                                     "Server",                                     gssdp_client_get_server_id (client));        /* SID header */        soup_message_headers_append (msg->response_headers,                                     "SID",                                     sid);        /* Timeout header */        if (timeout > 0)                tmp = g_strdup_printf ("Second-%d", timeout);        else                tmp = g_strdup ("infinite");        soup_message_headers_append (msg->response_headers,                                     "Timeout",                                     tmp);        g_free (tmp);        /* 200 OK */        soup_message_set_status (msg, SOUP_STATUS_OK);}/* Generates a new SID */static char *generate_sid (void){        uuid_t id;        char out[39];        uuid_generate (id);        uuid_unparse (id, out);        return g_strdup_printf ("uuid:%s", out);}/* Subscription expired */static gbooleansubscription_timeout (gpointer user_data){        SubscriptionData *data;        data = user_data;        g_hash_table_remove (data->service->priv->subscriptions, data->sid);        return FALSE;}/* Parse timeout header and return its value in seconds, or 0 * if infinite */static intparse_and_limit_timeout (const char *timeout){        int timeout_seconds;        timeout_seconds = 0;        if (strncmp (timeout, "Second-", strlen ("Second-")) == 0) {                /* We have a finite timeout */                timeout_seconds = CLAMP (atoi (timeout + strlen ("Second-")),                                         GENA_MIN_TIMEOUT,                                         GENA_MAX_TIMEOUT);        } else                timeout_seconds = GENA_MAX_TIMEOUT;        return timeout_seconds;}/* Subscription request */static voidsubscribe (GUPnPService *service,           SoupMessage  *msg,           const char   *callback,           const char   *timeout){        SubscriptionData *data;        char *start, *end, *uri;        int timeout_seconds;        GQueue *queue;        char *mem;        GList *l;        data = g_slice_new0 (SubscriptionData);        /* Parse callback list */        start = (char *) callback;        while ((start = strchr (start, '<'))) {                start += 1;                if (!start || !*start)                        break;                end = strchr (start, '>');                if (!end || !*end)                        break;                if (strncmp (start, "http://", strlen ("http://")) == 0) {                        uri = g_strndup (start, end - start);                        data->callbacks = g_list_append (data->callbacks, uri);                }                start = end;        }        if (!data->callbacks) {                soup_message_set_status (msg, SOUP_STATUS_PRECONDITION_FAILED);                g_slice_free (SubscriptionData, data);                return;        }        /* Add service and SID */        data->service = service;        data->sid     = generate_sid ();        /* Add timeout */        timeout_seconds = parse_and_limit_timeout (timeout);        if (timeout_seconds > 0) {                data->timeout_id = g_timeout_add_seconds (timeout_seconds,                                                          subscription_timeout,                                                          data);        }        /* Add to hash */        g_hash_table_insert (service->priv->subscriptions,                             data->sid,                             data);        /* Respond */        subscription_response (service, msg, data->sid, timeout_seconds);        /* Send initial event message */        queue = g_queue_new ();        for (l = service->priv->state_variables; l; l = l->next) {                NotifyData *ndata;                ndata = g_slice_new0 (NotifyData);                g_signal_emit (service,                               signals[QUERY_VARIABLE],                               g_quark_from_string (l->data),                               l->data,                               &ndata->value);                if (!G_IS_VALUE (&ndata->value)) {                        g_slice_free (NotifyData, ndata);                        continue;                }                ndata->variable = g_strdup (l->data);                g_queue_push_tail (queue, ndata);        }        mem = create_property_set (queue);        notify_subscriber (data->sid, data, mem);        /* Cleanup */        g_queue_free (queue);        g_free (mem);}/* Resubscription request */static voidresubscribe (GUPnPService *service,             SoupMessage  *msg,             const char   *sid,             const char   *timeout){        SubscriptionData *data;        int timeout_seconds;        data = g_hash_table_lookup (service->priv->subscriptions, sid);        if (!data) {                soup_message_set_status (msg, SOUP_STATUS_PRECONDITION_FAILED);                return;        }        /* Update timeout */        if (data->timeout_id) {                g_source_remove (data->timeout_id);                data->timeout_id = 0;        }        timeout_seconds = parse_and_limit_timeout (timeout);        if (timeout_seconds > 0) {                data->timeout_id = g_timeout_add_seconds (timeout_seconds,                                                          subscription_timeout,                                                          data);        }        /* Respond */        subscription_response (service, msg, sid, timeout_seconds);}

⌨️ 快捷键说明

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