gupnp-context.c

来自「另一 UPNP SDK 支持在UNIX/LINUX上运行。 UPnP是一种网络协」· C语言 代码 · 共 949 行 · 第 1/2 页

C
949
字号
 * Makes an URL that refers to our server. **/static char *make_server_url (GUPnPContext *context){        SoupServer *server;        guint port;        if (context->priv->host_ip == NULL)                context->priv->host_ip = get_default_host_ip ();        /* What port are we running on? */        server = gupnp_context_get_server (context);        port = soup_server_get_port (server);        /* Put it all together */        return g_strdup_printf ("http://%s:%u", context->priv->host_ip, port);}const char *_gupnp_context_get_server_url (GUPnPContext *context){        if (context->priv->server_url == NULL)                context->priv->server_url = make_server_url (context);        return (const char *) context->priv->server_url;}/** * gupnp_context_new * @main_context: A #GMainContext, or %NULL to use the default one * @host_ip: The local host's IP address, or %NULL to use the IP address * of the first non-loopback network interface. * @port: Port to run on, or 0 if you don't care what port is used. * @error: A location to store a #GError, or %NULL * * Create a new #GUPnPContext with the specified @main_context, @host_ip and @port. * * Return value: A new #GUPnPContext object, or %NULL on an error **/GUPnPContext *gupnp_context_new (GMainContext *main_context,                   const char   *host_ip,                   guint         port,                   GError      **error){        return g_object_new (GUPNP_TYPE_CONTEXT,                             "main-context", main_context,                             "host-ip", host_ip,                             "port", port,                             "error", error,                             NULL);}/** * gupnp_context_get_host_ip * @context: A #GUPnPContext * * Get the IP address we advertise ourselves as using. * * Return value: The IP address. This string should not be freed. **/const char *gupnp_context_get_host_ip (GUPnPContext *context){        g_return_val_if_fail (GUPNP_IS_CONTEXT (context), NULL);        if (context->priv->host_ip == NULL)                context->priv->host_ip = get_default_host_ip ();        return context->priv->host_ip;}/** * gupnp_context_get_port * @context: A #GUPnPContext * * Get the port that the SOAP server is running on.  * Return value: The port the SOAP server is running on. **/guintgupnp_context_get_port (GUPnPContext *context){        SoupServer *server;        g_return_val_if_fail (GUPNP_IS_CONTEXT (context), 0);        server = gupnp_context_get_server (context);        return soup_server_get_port (server);}/** * gupnp_context_set_subscription_timeout * @context: A #GUPnPContext * @timeout: Event subscription timeout in seconds * * Sets the event subscription timeout to @timeout. Use 0 if you don't * want subscriptions to time out. Note that any client side subscriptions * will automatically be renewed. **/voidgupnp_context_set_subscription_timeout (GUPnPContext *context,                                        guint         timeout){        g_return_if_fail (GUPNP_IS_CONTEXT (context));        context->priv->subscription_timeout = timeout;        g_object_notify (G_OBJECT (context), "subscription-timeout");}/** * gupnp_context_get_subscription_timeout * @context: A #GUPnPContext * * Get the event subscription timeout (in seconds), or 0 meaning there is no * timeout. *  * Return value: The event subscription timeout in seconds. **/guintgupnp_context_get_subscription_timeout (GUPnPContext *context){        g_return_val_if_fail (GUPNP_IS_CONTEXT (context), 0);        return context->priv->subscription_timeout;}/* Construct a local path from @requested path, removing the last slash * if any to make sure we append the locale suffix in a canonical way. */static char *construct_local_path (const char   *requested_path,                      HostPathData *host_path_data){        GString *str;        int len;        if (!requested_path || *requested_path == 0)                return g_strdup (host_path_data->local_path);        if (*requested_path != '/')                return NULL; /* Absolute paths only */        str = g_string_new (host_path_data->local_path);        /* Skip the length of the path relative to which @requested_path         * is specified. */        requested_path += strlen (host_path_data->server_path);        /* Strip the last slashes to make sure we append the locale suffix         * in a canonical way. */        len = strlen (requested_path);        while (requested_path[len - 1] == '/')                len--;        g_string_append_len (str,                             requested_path,                             len);        return g_string_free (str, FALSE);}/* Append locale suffix to @local_path. */static char *append_locale (const char *local_path, GList *locales){        if (!locales)                return g_strdup (local_path);        return g_strdup_printf ("%s.%s",                                local_path,                                (char *) locales->data);}/* Redirect @msg to the same URI, but with a slash appended. */static voidredirect_to_folder (SoupMessage *msg){        char *uri, *redir_uri;        uri = soup_uri_to_string (soup_message_get_uri (msg),                                  FALSE);        redir_uri = g_strdup_printf ("%s/", uri);        soup_message_headers_append (msg->response_headers,                                     "Location", redir_uri);        soup_message_set_status (msg,                                 SOUP_STATUS_MOVED_PERMANENTLY);        g_free (redir_uri);        g_free (uri);}/* Serve @path. Note that we do not need to check for path including bogus * '..' as libsoup does this for us. */static voidhost_path_handler (SoupServer        *server,                   SoupMessage       *msg,                    const char        *path,                   GHashTable        *query,                   SoupClientContext *client,                   gpointer           user_data){        char *local_path, *path_to_open;        struct stat st;        int status;        GList *locales;        GMappedFile *mapped_file;        GError *error;        locales      = NULL;        local_path   = NULL;        path_to_open = NULL;        if (msg->method != SOUP_METHOD_GET &&            msg->method != SOUP_METHOD_HEAD) {                soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);                goto DONE;        }        /* Construct base local path */        local_path = construct_local_path (path, (HostPathData *) user_data);        if (!local_path) {                soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST);                goto DONE;        }        /* Get preferred locales */        locales = http_request_get_accept_locales (msg); AGAIN:        /* Add locale suffix if available */        path_to_open = append_locale (local_path, locales);        /* See what we've got */        if (g_stat (path_to_open, &st) == -1) {                if (errno == EPERM)                        soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);                else if (errno == ENOENT) {                        if (locales) {                                g_free (path_to_open);                                locales = locales->next;                                goto AGAIN;                        } else                                soup_message_set_status (msg,                                                         SOUP_STATUS_NOT_FOUND);                } else                        soup_message_set_status                                (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);                goto DONE;        }        /* Handle directories */        if (S_ISDIR (st.st_mode)) {                if (!g_str_has_suffix (path, "/")) {                        redirect_to_folder (msg);                        goto DONE;                }                /* This incorporates the locale portion in the folder name                 * intentionally. */                g_free (local_path);                local_path = g_build_filename (path_to_open,                                               "index.html",                                               NULL);                g_free (path_to_open);                goto AGAIN;        }        /* Map file */        error = NULL;        mapped_file = g_mapped_file_new (path_to_open, FALSE, &error);        if (mapped_file == NULL) {                g_warning ("Unable to map file %s: %s",                           path_to_open, error->message);                g_error_free (error);                soup_message_set_status (msg,                                         SOUP_STATUS_INTERNAL_SERVER_ERROR);                goto DONE;        }        /* Handle method (GET or HEAD) */        status = SOUP_STATUS_OK;        if (msg->method == SOUP_METHOD_GET) {                gsize offset, length;                gboolean have_range;                SoupBuffer *buffer;                /* Find out range */                have_range = FALSE;                offset = 0;                length = st.st_size;                if (!http_request_get_range (msg,                                             &have_range,                                             &offset,                                             &length)) {                        soup_message_set_status                                (msg,                                 SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE);                        g_free (path_to_open);                        goto DONE;                }                if (have_range && (length < 0                   ||                                   offset < 0                   ||                                   length > st.st_size - offset ||                                   offset >= st.st_size)) {                        soup_message_set_status                                (msg,                                 SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE);                        g_free (path_to_open);                        goto DONE;                }                /* Add requested content */                buffer = soup_buffer_new_with_owner                             (g_mapped_file_get_contents (mapped_file) + offset,                              length,                              mapped_file,                              (GDestroyNotify) g_mapped_file_free);                soup_message_body_append_buffer (msg->response_body, buffer);                soup_buffer_free (buffer);                /* Set status */                if (have_range) {                        http_response_set_content_range (msg,                                                         offset,                                                         offset + length,                                                         st.st_size);                        status = SOUP_STATUS_PARTIAL_CONTENT;                }        } else if (msg->method == SOUP_METHOD_HEAD) {                char *length;                length = g_strdup_printf ("%lu", (gulong) st.st_size);		soup_message_headers_append (msg->response_headers,					     "Content-Length",                                             length);		g_free (length);        } else {                g_assert_not_reached ();        }        /* Set Content-Type */        http_response_set_content_type (msg,                                        path_to_open,                                         (guchar *) g_mapped_file_get_contents                                                                (mapped_file),                                        st.st_size);        /* Set Content-Language */        if (locales)               http_response_set_content_locale (msg, locales->data);        /* Set Accept-Ranges */        soup_message_headers_append (msg->response_headers,                                     "Accept-Ranges",                                     "bytes");        /* Set status */        soup_message_set_status (msg, status); DONE:        /* Cleanup */        g_free (path_to_open);        g_free (local_path);        while (locales) {                g_free (locales->data);                locales = g_list_delete_link (locales, locales);        }}HostPathData *host_path_data_new (const char *local_path,                    const char *server_path){        HostPathData *path_data;        path_data = g_slice_new (HostPathData);        path_data->local_path  = g_strdup (local_path);        path_data->server_path = g_strdup (server_path);        return path_data;}voidhost_path_data_free (HostPathData *path_data){        g_free (path_data->local_path);        g_free (path_data->server_path);        g_slice_free (HostPathData, path_data);}/** * gupnp_context_host_path * @context: A #GUPnPContext * @local_path: Path to the local file or folder to be hosted * @server_path: Web server path where @local_path should be hosted * * Start hosting @local_path at @server_path. Files with the path * @local_path.LOCALE (if they exist) will be served up when LOCALE is * specified in the request's Accept-Language header. **/voidgupnp_context_host_path (GUPnPContext *context,                         const char   *local_path,                         const char   *server_path){        SoupServer *server;        HostPathData *path_data;        g_return_if_fail (GUPNP_IS_CONTEXT (context));        g_return_if_fail (local_path != NULL);        g_return_if_fail (server_path != NULL);        server = gupnp_context_get_server (context);        path_data = host_path_data_new (local_path, server_path);        soup_server_add_handler (server,                                 server_path,                                 host_path_handler,                                 path_data,                                 (GDestroyNotify) host_path_data_free);}/** * gupnp_context_unhost_path * @context: A #GUPnPContext * @server_path: Web server path where the file or folder is hosted * * Stop hosting the file or folder at @server_path. **/voidgupnp_context_unhost_path (GUPnPContext *context,                           const char   *server_path){        SoupServer *server;        g_return_if_fail (GUPNP_IS_CONTEXT (context));        g_return_if_fail (server_path != NULL);        server = gupnp_context_get_server (context);        soup_server_remove_handler (server, server_path);}

⌨️ 快捷键说明

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