gupnp-context.c

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

C
949
字号
/* * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd. * * Author: Jorn Baayen <jorn@openedhand.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. *//** * SECTION:gupnp-context * @short_description: Context object wrapping shared networking bits. * * #GUPnPContext wraps the networking bits that are used by the various * GUPnP classes. It automatically starts a web server on demand. * * For debugging, it is possible to see the messages being sent and received by * exporting #GUPNP_DEBUG. */#include <config.h>#include <errno.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <stdlib.h>#include <stdio.h>#include <sys/utsname.h>#include <sys/ioctl.h>#include <sys/socket.h>#include <sys/types.h>#include <sys/stat.h>#include <arpa/inet.h>#include <net/if.h>#include <ifaddrs.h>#include <libsoup/soup-address.h>#include <glib/gstdio.h>#include "gupnp-context.h"#include "gupnp-context-private.h"#include "gupnp-marshal.h"#include "gena-protocol.h"#include "http-headers.h"G_DEFINE_TYPE (GUPnPContext,               gupnp_context,               GSSDP_TYPE_CLIENT);struct _GUPnPContextPrivate {        char        *host_ip;        guint        port;        guint        subscription_timeout;        SoupSession *session;        SoupServer  *server; /* Started on demand */        char        *server_url;};enum {        PROP_0,        PROP_HOST_IP,        PROP_PORT,        PROP_SERVER,        PROP_SUBSCRIPTION_TIMEOUT};#define LOOPBACK_IP "127.0.0.1"typedef struct {        char *local_path;        char *server_path;} HostPathData;/* * Generates the default server ID. **/static char *make_server_id (void){        struct utsname sysinfo;        uname (&sysinfo);        return g_strdup_printf ("%s/%s UPnP/1.0 GUPnP/%s",                                sysinfo.sysname,                                sysinfo.version,                                VERSION);}/* * Get the host IP for the specified interface, or the first up and non-loopback * interface if no name is specified. */static char *get_host_ip (const char *name){        struct ifaddrs *ifa_list, *ifa;        char *ret;        ret = NULL;        if (getifaddrs (&ifa_list) != 0) {                g_error ("Failed to retrieve list of network interfaces:\n%s\n",                         strerror (errno));                return NULL;        }        for (ifa = ifa_list; ifa != NULL; ifa = ifa->ifa_next) {                char ip[INET6_ADDRSTRLEN];                const char *p;                struct sockaddr_in *s4;                struct sockaddr_in6 *s6;                if (ifa->ifa_addr == NULL)                        continue;                if ((ifa->ifa_flags & IFF_LOOPBACK) ||                    !(ifa->ifa_flags & IFF_UP))                        continue;                /* If a name was specified, check it */                if (name && strcmp (name, ifa->ifa_name) != 0)                        continue;                                p = NULL;                switch (ifa->ifa_addr->sa_family) {                case AF_INET:                        s4 = (struct sockaddr_in *) ifa->ifa_addr;                        p = inet_ntop (AF_INET,                                       &s4->sin_addr, ip, sizeof (ip));                        break;                case AF_INET6:                        s6 = (struct sockaddr_in6 *) ifa->ifa_addr;                        p = inet_ntop (AF_INET6,                                       &s6->sin6_addr, ip, sizeof (ip));                        break;                default:                        continue; /* Unknown: ignore */                }                if (p != NULL) {                        ret = g_strdup (p);                        break;                }        }        freeifaddrs (ifa_list);        if (!ret) {                /* Didn't find anything. Let's take the loopback IP. */                ret = g_strdup (LOOPBACK_IP);        }        return ret;}/* * Get the host IP of the interface used for the default route.  On any error, * the first up and non-loopback interface is used. */static char *get_default_host_ip (void){        FILE *fp;        int ret;        char dev[32];        unsigned long dest;        gboolean found = FALSE;                /* TODO: error checking */        fp = fopen ("/proc/net/route", "r");                /* Skip the header */        fscanf (fp, "%*[^\n]\n");                while ((ret = fscanf (fp,                              "%31s %lx %*x %*X %*d %*d %*d %*x %*d %*d %*d",                              dev, &dest)) != EOF) {                /* If we got a device name and destination, and the destination                   is 0, then we have the default route */                if (ret == 2 && dest == 0) {                        found = TRUE;                        break;                }        }                fclose (fp);        return get_host_ip (found ? dev : NULL);}static voidgupnp_context_init (GUPnPContext *context){        char *server_id;        context->priv =                G_TYPE_INSTANCE_GET_PRIVATE (context,                                             GUPNP_TYPE_CONTEXT,                                             GUPnPContextPrivate);        context->priv->session = soup_session_async_new ();        g_object_set (context->priv->session,                      SOUP_SESSION_IDLE_TIMEOUT,                      60,                      NULL);        server_id = make_server_id ();        gssdp_client_set_server_id (GSSDP_CLIENT (context), server_id);        g_free (server_id);	if (g_getenv ("GUPNP_DEBUG")) {		SoupLogger *logger;		logger = soup_logger_new (SOUP_LOGGER_LOG_BODY, -1);		soup_logger_attach (logger, context->priv->session);	}}static voidgupnp_context_set_property (GObject      *object,                            guint         property_id,                            const GValue *value,                            GParamSpec   *pspec){        GUPnPContext *context;        context = GUPNP_CONTEXT (object);        switch (property_id) {        case PROP_HOST_IP:                context->priv->host_ip = g_value_dup_string (value);                break;        case PROP_PORT:                context->priv->port = g_value_get_uint (value);                break;        case PROP_SUBSCRIPTION_TIMEOUT:                context->priv->subscription_timeout = g_value_get_uint (value);                break;        default:                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);                break;        }}static voidgupnp_context_get_property (GObject    *object,                            guint       property_id,                            GValue     *value,                            GParamSpec *pspec){        GUPnPContext *context;        context = GUPNP_CONTEXT (object);        switch (property_id) {        case PROP_HOST_IP:                g_value_set_string (value,                                    gupnp_context_get_host_ip (context));                break;        case PROP_PORT:                g_value_set_uint (value,                                  gupnp_context_get_port (context));                break;        case PROP_SERVER:                g_value_set_object (value,                                    gupnp_context_get_server (context));                break;        case PROP_SUBSCRIPTION_TIMEOUT:                g_value_set_uint (value,                                  gupnp_context_get_subscription_timeout                                                                   (context));                break;        default:                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);                break;        }}static voidgupnp_context_dispose (GObject *object){        GUPnPContext *context;        GObjectClass *object_class;        context = GUPNP_CONTEXT (object);        if (context->priv->session) {                g_object_unref (context->priv->session);                context->priv->session = NULL;        }        if (context->priv->server) {                g_object_unref (context->priv->server);                context->priv->server = NULL;        }        /* Call super */        object_class = G_OBJECT_CLASS (gupnp_context_parent_class);        object_class->dispose (object);}static voidgupnp_context_finalize (GObject *object){        GUPnPContext *context;        GObjectClass *object_class;        context = GUPNP_CONTEXT (object);        g_free (context->priv->host_ip);        g_free (context->priv->server_url);        /* Call super */        object_class = G_OBJECT_CLASS (gupnp_context_parent_class);        object_class->finalize (object);}static voidgupnp_context_class_init (GUPnPContextClass *klass){        GObjectClass *object_class;        object_class = G_OBJECT_CLASS (klass);        object_class->set_property = gupnp_context_set_property;        object_class->get_property = gupnp_context_get_property;        object_class->dispose      = gupnp_context_dispose;        object_class->finalize     = gupnp_context_finalize;        g_type_class_add_private (klass, sizeof (GUPnPContextPrivate));        /**         * GUPnPContext:host-ip         *         * The local host's IP address. Set to NULL to autodetect.         **/        g_object_class_install_property                (object_class,                 PROP_HOST_IP,                 g_param_spec_string ("host-ip",                                      "Host IP",                                      "The local host's IP address",                                      NULL,                                      G_PARAM_READWRITE |                                      G_PARAM_CONSTRUCT_ONLY |                                      G_PARAM_STATIC_NAME |                                      G_PARAM_STATIC_NICK |                                      G_PARAM_STATIC_BLURB));        /**         * GUPnPContext:port         *         * The port to run on. Set to 0 if you don't care what port to run on.         **/        g_object_class_install_property                (object_class,                 PROP_PORT,                 g_param_spec_uint ("port",                                    "Port",                                    "Port to run on",                                    0, G_MAXUINT, SOUP_ADDRESS_ANY_PORT,                                    G_PARAM_READWRITE |                                    G_PARAM_CONSTRUCT_ONLY |                                    G_PARAM_STATIC_NAME |                                    G_PARAM_STATIC_NICK |                                    G_PARAM_STATIC_BLURB));        /**         * GUPnPContext:server         *         * The #SoupServer HTTP server used by GUPnP.         **/        g_object_class_install_property                (object_class,                 PROP_SERVER,                 g_param_spec_object ("server",                                      "SoupServer",                                      "SoupServer HTTP server",                                      SOUP_TYPE_SERVER,                                      G_PARAM_READABLE |                                      G_PARAM_STATIC_NAME |                                      G_PARAM_STATIC_NICK |                                      G_PARAM_STATIC_BLURB));        /**         * GUPnPContext:subscription-timeout         *         * The preferred subscription timeout: the number of seconds after         * which subscriptions are renewed. Set to '0' if subscriptions          * are never to time out.         **/        g_object_class_install_property                (object_class,                 PROP_SUBSCRIPTION_TIMEOUT,                 g_param_spec_uint ("subscription-timeout",                                    "Subscription timeout",                                    "Subscription timeout",                                    0,                                    GENA_MAX_TIMEOUT,                                    GENA_DEFAULT_TIMEOUT,                                    G_PARAM_READWRITE |                                    G_PARAM_CONSTRUCT_ONLY |                                    G_PARAM_STATIC_NAME |                                    G_PARAM_STATIC_NICK |                                    G_PARAM_STATIC_BLURB));}SoupSession *_gupnp_context_get_session (GUPnPContext *context){        return context->priv->session;}/* * Default server handler: Return 404 not found. **/static voiddefault_server_handler (SoupServer        *server,                        SoupMessage       *msg,                         const char        *path,                        GHashTable        *query,                        SoupClientContext *client,                        gpointer           user_data){        soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND);}/** * gupnp_context_get_server * @context: A #GUPnPContext * * Get the #SoupServer HTTP server that GUPnP is using. * * Return value: The #SoupServer used by GUPnP.  Do not unref this when finished. **/SoupServer *gupnp_context_get_server (GUPnPContext *context){        g_return_val_if_fail (GUPNP_IS_CONTEXT (context), NULL);        if (context->priv->server == NULL) {                context->priv->server = soup_server_new (SOUP_SERVER_PORT,                                                         context->priv->port,                                                         NULL);                soup_server_add_handler (context->priv->server, NULL,                                         default_server_handler, context,                                         NULL);                soup_server_run_async (context->priv->server);        }        return context->priv->server;}/*

⌨️ 快捷键说明

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