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

📄 upnp.c

📁 GNUnet是一个安全的点对点网络框架
💻 C
📖 第 1 页 / 共 2 页
字号:
/**
 * @file upnp.c UPnP Implementation
 * @ingroup core
 *
 * gaim
 *
 * Gaim is the legal property of its developers, whose names are too numerous
 * to list here.  Please refer to the COPYRIGHT file distributed with this
 * source distribution.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "platform.h"
#include "xmlnode.h"
#include "util.h"
#include "upnp.h"
#include "error.h"
#include "ip.h"

#include <curl/curl.h>

#define TRUE GNUNET_YES
#define FALSE GNUNET_NO
#define g_return_if_fail(a) if(!(a)) return;
#define g_return_val_if_fail(a, val) if(!(a)) return (val);

#define HTTP_OK "200 OK"
#define NUM_UDP_ATTEMPTS 2
#define HTTPMU_HOST_ADDRESS "239.255.255.250"
#define HTTPMU_HOST_PORT 1900
#define SEARCH_REQUEST_DEVICE "urn:schemas-upnp-org:service:%s"
#define SEARCH_REQUEST_STRING \
  "M-SEARCH * HTTP/1.1\r\n" \
  "MX: 2\r\n" \
  "HOST: 239.255.255.250:1900\r\n" \
  "MAN: \"ssdp:discover\"\r\n" \
  "ST: urn:schemas-upnp-org:service:%s\r\n" \
  "\r\n"
#define WAN_IP_CONN_SERVICE "WANIPConnection:1"
#define WAN_PPP_CONN_SERVICE "WANPPPConnection:1"
#define HTTP_POST_SOAP_HEADER \
        "SOAPACTION: \"urn:schemas-upnp-org:service:%s#%s\""
#define HTTP_POST_SIZE_HEADER "CONTENT-LENGTH: %u"
#define SOAP_ACTION \
  "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" \
  "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" " \
  	"s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n" \
    "<s:Body>\r\n" \
      "<u:%s xmlns:u=\"urn:schemas-upnp-org:service:%s\">\r\n" \
        "%s" \
      "</u:%s>\r\n" \
    "</s:Body>\r\n" \
  "</s:Envelope>"
#define PORT_MAPPING_LEASE_TIME "0"
#define PORT_MAPPING_DESCRIPTION "GNUNET_UPNP_PORT_FORWARD"
#define ADD_PORT_MAPPING_PARAMS \
  "<NewRemoteHost></NewRemoteHost>\r\n" \
  "<NewExternalPort>%i</NewExternalPort>\r\n" \
  "<NewProtocol>%s</NewProtocol>\r\n" \
  "<NewInternalPort>%i</NewInternalPort>\r\n" \
  "<NewInternalClient>%s</NewInternalClient>\r\n" \
  "<NewEnabled>1</NewEnabled>\r\n" \
  "<NewPortMappingDescription>" \
  PORT_MAPPING_DESCRIPTION \
  "</NewPortMappingDescription>\r\n" \
  "<NewLeaseDuration>" \
  PORT_MAPPING_LEASE_TIME \
  "</NewLeaseDuration>\r\n"
#define DELETE_PORT_MAPPING_PARAMS \
  "<NewRemoteHost></NewRemoteHost>\r\n" \
  "<NewExternalPort>%i</NewExternalPort>\r\n" \
  "<NewProtocol>%s</NewProtocol>\r\n"

typedef enum
{
  GAIM_UPNP_STATUS_UNDISCOVERED = -1,
  GAIM_UPNP_STATUS_UNABLE_TO_DISCOVER,
  GAIM_UPNP_STATUS_DISCOVERING,
  GAIM_UPNP_STATUS_DISCOVERED
} GaimUPnPStatus;

typedef struct
{
  GaimUPnPStatus status;
  char *control_url;
  const char *service_type;
  char publicip[16];
} GaimUPnPControlInfo;

typedef struct
{
  const char *service_type;
  char *full_url;
  char *buf;
  unsigned int buf_len;
  int sock;
} UPnPDiscoveryData;

static GaimUPnPControlInfo control_info = {
  GAIM_UPNP_STATUS_UNDISCOVERED,
  NULL,
  NULL,
  "",
};

/**
 * This is the signature used for functions that act as a callback
 * to CURL.
 */
typedef size_t (*GaimUtilFetchUrlCallback) (void *url_data,
                                            size_t size,
                                            size_t nmemb, void *user_data);



static char *
g_strstr_len (const char *haystack, int haystack_len, const char *needle)
{
  int i;

  g_return_val_if_fail (haystack != NULL, NULL);
  g_return_val_if_fail (needle != NULL, NULL);

  if (haystack_len < 0)
    return strstr (haystack, needle);
  else
    {
      const char *p = haystack;
      int needle_len = strlen (needle);
      const char *end = haystack + haystack_len - needle_len;

      if (needle_len == 0)
        return (char *) haystack;

      while (*p && p <= end)
        {
          for (i = 0; i < needle_len; i++)
            if (p[i] != needle[i])
              goto next;

          return (char *) p;

        next:
          p++;
        }
    }

  return NULL;
}

static int
gaim_upnp_compare_device (const xmlnode * device, const char *deviceType)
{
  xmlnode *deviceTypeNode = xmlnode_get_child (device, "deviceType");
  char *tmp;
  int ret;

  if (deviceTypeNode == NULL)
    return FALSE;
  tmp = xmlnode_get_data (deviceTypeNode);
  ret = !strcasecmp (tmp, deviceType);
  GNUNET_free (tmp);
  return ret;
}

static int
gaim_upnp_compare_service (const xmlnode * service, const char *serviceType)
{
  xmlnode *serviceTypeNode;
  char *tmp;
  int ret;

  if (service == NULL)
    return FALSE;
  serviceTypeNode = xmlnode_get_child (service, "serviceType");
  if (serviceTypeNode == NULL)
    return FALSE;
  tmp = xmlnode_get_data (serviceTypeNode);
  ret = !strcasecmp (tmp, serviceType);
  GNUNET_free (tmp);
  return ret;
}

static char *
gaim_upnp_parse_description_response (const char *httpResponse,
                                      size_t len,
                                      const char *httpURL,
                                      const char *serviceType)
{
  char *xmlRoot, *baseURL, *controlURL, *service;
  xmlnode *xmlRootNode, *serviceTypeNode, *controlURLNode, *baseURLNode;
  char *tmp;

  /* find the root of the xml document */
  xmlRoot = g_strstr_len (httpResponse, len, "<root");
  if (xmlRoot == NULL)
    return NULL;
  if (g_strstr_len (httpResponse, len, "</root") == NULL)
    return NULL;

  /* create the xml root node */
  xmlRootNode = xmlnode_from_str (xmlRoot, len - (xmlRoot - httpResponse));
  if (xmlRootNode == NULL)
    return NULL;

  /* get the baseURL of the device */
  baseURLNode = xmlnode_get_child (xmlRootNode, "URLBase");
  if (baseURLNode != NULL)
    {
      baseURL = xmlnode_get_data (baseURLNode);
    }
  else
    {
      baseURL = GNUNET_strdup (httpURL);
    }

  /* get the serviceType child that has the service type as its data */
  /* get urn:schemas-upnp-org:device:InternetGatewayDevice:1 and its devicelist */
  serviceTypeNode = xmlnode_get_child (xmlRootNode, "device");
  while (!gaim_upnp_compare_device (serviceTypeNode,
                                    "urn:schemas-upnp-org:device:InternetGatewayDevice:1")
         && serviceTypeNode != NULL)
    {
      serviceTypeNode = xmlnode_get_next_twin (serviceTypeNode);
    }
  if (serviceTypeNode == NULL)
    {
      GNUNET_free (baseURL);
      xmlnode_free (xmlRootNode);
      return NULL;
    }
  serviceTypeNode = xmlnode_get_child (serviceTypeNode, "deviceList");
  if (serviceTypeNode == NULL)
    {
      GNUNET_free (baseURL);
      xmlnode_free (xmlRootNode);
      return NULL;
    }

  /* get urn:schemas-upnp-org:device:WANDevice:1 and its devicelist */
  serviceTypeNode = xmlnode_get_child (serviceTypeNode, "device");
  while (!gaim_upnp_compare_device (serviceTypeNode,
                                    "urn:schemas-upnp-org:device:WANDevice:1")
         && serviceTypeNode != NULL)
    {
      serviceTypeNode = xmlnode_get_next_twin (serviceTypeNode);
    }
  if (serviceTypeNode == NULL)
    {
      GNUNET_free (baseURL);
      xmlnode_free (xmlRootNode);
      return NULL;
    }
  serviceTypeNode = xmlnode_get_child (serviceTypeNode, "deviceList");
  if (serviceTypeNode == NULL)
    {
      GNUNET_free (baseURL);
      xmlnode_free (xmlRootNode);
      return NULL;
    }

  /* get urn:schemas-upnp-org:device:WANConnectionDevice:1 and its servicelist */
  serviceTypeNode = xmlnode_get_child (serviceTypeNode, "device");
  while (serviceTypeNode && !gaim_upnp_compare_device (serviceTypeNode,
                                                       "urn:schemas-upnp-org:device:WANConnectionDevice:1"))
    {
      serviceTypeNode = xmlnode_get_next_twin (serviceTypeNode);
    }
  if (serviceTypeNode == NULL)
    {
      GNUNET_free (baseURL);
      xmlnode_free (xmlRootNode);
      return NULL;
    }
  serviceTypeNode = xmlnode_get_child (serviceTypeNode, "serviceList");
  if (serviceTypeNode == NULL)
    {
      GNUNET_free (baseURL);
      xmlnode_free (xmlRootNode);
      return NULL;
    }

  /* get the serviceType variable passed to this function */
  service = g_strdup_printf (SEARCH_REQUEST_DEVICE, serviceType);
  serviceTypeNode = xmlnode_get_child (serviceTypeNode, "service");
  while (!gaim_upnp_compare_service (serviceTypeNode, service) &&
         serviceTypeNode != NULL)
    {
      serviceTypeNode = xmlnode_get_next_twin (serviceTypeNode);
    }

  GNUNET_free (service);
  if (serviceTypeNode == NULL)
    {
      GNUNET_free (baseURL);
      xmlnode_free (xmlRootNode);
      return NULL;
    }

  /* get the controlURL of the service */
  if ((controlURLNode = xmlnode_get_child (serviceTypeNode,
                                           "controlURL")) == NULL)
    {
      GNUNET_free (baseURL);
      xmlnode_free (xmlRootNode);
      return NULL;
    }

  tmp = xmlnode_get_data (controlURLNode);
  if (baseURL && !gaim_str_has_prefix (tmp, "http://") &&
      !gaim_str_has_prefix (tmp, "HTTP://"))
    {
      if (tmp[0] == '/')
        {
          size_t len;
          const char *end;
          /* absolute path */
          end = strstr (&baseURL[strlen ("http://")], "/");
          if (end == NULL)
            len = strlen (&baseURL[strlen ("http://")]);
          else
            len = end - &baseURL[strlen ("http://")];
          controlURL = g_strdup_printf ("http://%.*s%s",
                                        len,
                                        &baseURL[strlen ("http://")], tmp);
        }
      else
        {
          controlURL = g_strdup_printf ("%s%s", baseURL, tmp);
        }
      GNUNET_free (tmp);
    }
  else
    {
      controlURL = tmp;
    }
  GNUNET_free (baseURL);
  xmlnode_free (xmlRootNode);

  return controlURL;
}

#define CURL_EASY_SETOPT(c, a, b) do { ret = curl_easy_setopt(c, a, b); if (ret != CURLE_OK) GNUNET_GE_LOG(NULL, GNUNET_GE_WARNING | GNUNET_GE_USER | GNUNET_GE_BULK, _("%s failed at %s:%d: `%s'\n"), "curl_easy_setopt", __FILE__, __LINE__, curl_easy_strerror(ret)); } while (0);

/**
 * Do the generic curl setup.
 */
static int
setup_curl (const char *proxy, CURL * curl)
{
  int ret;

  CURL_EASY_SETOPT (curl, CURLOPT_FAILONERROR, 1);
  if (strlen (proxy) > 0)

⌨️ 快捷键说明

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