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 + -
显示快捷键?