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

📄 upnp.c

📁 GNUnet是一个安全的点对点网络框架
💻 C
📖 第 1 页 / 共 2 页
字号:
    CURL_EASY_SETOPT (curl, CURLOPT_PROXY, proxy);
  CURL_EASY_SETOPT (curl, CURLOPT_BUFFERSIZE, 1024);    /* a bit more than one HELLO */
  CURL_EASY_SETOPT (curl, CURLOPT_CONNECTTIMEOUT, 150L);
  /* NOTE: use of CONNECTTIMEOUT without also
     setting NOSIGNAL results in really weird
     crashes on my system! */
  CURL_EASY_SETOPT (curl, CURLOPT_NOSIGNAL, 1);
  return GNUNET_OK;
}

static int
gaim_upnp_generate_action_message_and_send (const char *proxy,
                                            const char *actionName,
                                            const char *actionParams,
                                            GaimUtilFetchUrlCallback cb,
                                            void *cb_data)
{
  CURL *curl;
  int ret;
  char *soapHeader;
  char *sizeHeader;
  char *soapMessage;
  struct curl_slist *headers = NULL;

  GNUNET_GE_ASSERT (NULL, cb != NULL);
  if (0 != curl_global_init (CURL_GLOBAL_WIN32))
    return GNUNET_SYSERR;
  /* set the soap message */
  soapMessage = g_strdup_printf (SOAP_ACTION,
                                 actionName,
                                 control_info.service_type,
                                 actionParams, actionName);
  soapHeader = g_strdup_printf (HTTP_POST_SOAP_HEADER,
                                control_info.service_type, actionName);
  sizeHeader = g_strdup_printf (HTTP_POST_SIZE_HEADER, strlen (soapMessage));
  curl = curl_easy_init ();
  setup_curl (proxy, curl);
  CURL_EASY_SETOPT (curl, CURLOPT_URL, control_info.control_url);
  CURL_EASY_SETOPT (curl, CURLOPT_WRITEFUNCTION, cb);
  CURL_EASY_SETOPT (curl, CURLOPT_WRITEDATA, cb_data);
  CURL_EASY_SETOPT (curl, CURLOPT_POST, 1);
  headers = curl_slist_append (headers,
                               "CONTENT-TYPE: text/xml ; charset=\"utf-8\"");
  headers = curl_slist_append (headers, soapHeader);
  headers = curl_slist_append (headers, sizeHeader);
  CURL_EASY_SETOPT (curl, CURLOPT_HTTPHEADER, headers);
  CURL_EASY_SETOPT (curl, CURLOPT_POSTFIELDS, soapMessage);
  CURL_EASY_SETOPT (curl, CURLOPT_POSTFIELDSIZE, strlen (soapMessage));
  CURL_EASY_SETOPT (curl, CURLOPT_MAXREDIRS, 1L);
  CURL_EASY_SETOPT (curl, CURLOPT_CONNECTTIMEOUT, 1L);
  CURL_EASY_SETOPT (curl, CURLOPT_TIMEOUT, 2L);
  /* NOTE: use of CONNECTTIMEOUT without also
     setting NOSIGNAL results in really weird
     crashes on my system! */
  CURL_EASY_SETOPT (curl, CURLOPT_NOSIGNAL, 1);
  if (ret == CURLE_OK)
    ret = curl_easy_perform (curl);
#if 0
  if (ret != CURLE_OK)
    GNUNET_GE_LOG (NULL,
                   GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_DEVELOPER |
                   GNUNET_GE_BULK,
                   _
                   ("%s failed for url `%s' and post-data `%s' at %s:%d: `%s'\n"),
                   "curl_easy_perform", control_info.control_url, soapMessage,
                   __FILE__, __LINE__, curl_easy_strerror (ret));
#endif
  curl_slist_free_all (headers);
  curl_easy_cleanup (curl);
  curl_global_cleanup ();
  GNUNET_free (sizeHeader);
  GNUNET_free (soapMessage);
  GNUNET_free (soapHeader);
  if (ret != CURLE_OK)
    return GNUNET_SYSERR;
  return GNUNET_OK;
}


static size_t
looked_up_public_ip_cb (void *url_data,
                        size_t size, size_t nmemb, void *user_data)
{
  UPnPDiscoveryData *dd = user_data;
  size_t len = size * nmemb;
  const char *temp;
  const char *temp2;

  if (len + dd->buf_len > 1024 * 1024 * 4)
    return 0;                   /* refuse to process - too big! */
  GNUNET_array_grow (dd->buf, dd->buf_len, dd->buf_len + len);
  memcpy (&dd->buf[dd->buf_len - len], url_data, len);
  if (dd->buf_len == 0)
    return len;
  /* extract the ip, or see if there is an error */
  if ((temp = g_strstr_len (dd->buf,
                            dd->buf_len, "<NewExternalIPAddress")) == NULL)
    return len;
  if (!(temp = g_strstr_len (temp, dd->buf_len - (temp - dd->buf), ">")))
    return len;
  if (!(temp2 = g_strstr_len (temp, dd->buf_len - (temp - dd->buf), "<")))
    return len;
  memset (control_info.publicip, 0, sizeof (control_info.publicip));
  if (temp2 - temp >= sizeof (control_info.publicip))
    temp2 = temp + sizeof (control_info.publicip) - 1;
  memcpy (control_info.publicip, temp + 1, temp2 - (temp + 1));
  GNUNET_GE_LOG (NULL,
                 GNUNET_GE_INFO | GNUNET_GE_USER | GNUNET_GE_BULK,
                 _("upnp: NAT Returned IP: %s\n"), control_info.publicip);
  return len;
}


static size_t
ignore_response (void *url_data, size_t size, size_t nmemb, void *user_data)
{
  return size * nmemb;
}

/**
 * Process downloaded bits of service description.
 */
static size_t
upnp_parse_description_cb (void *httpResponse,
                           size_t size, size_t nmemb, void *user_data)
{
  UPnPDiscoveryData *dd = user_data;
  size_t len = size * nmemb;
  char *control_url = NULL;

  if (len + dd->buf_len > 1024 * 1024 * 4)
    return len;                 /* refuse to process - too big! */
  GNUNET_array_grow (dd->buf, dd->buf_len, dd->buf_len + len);
  memcpy (&dd->buf[dd->buf_len - len], httpResponse, len);
  if (dd->buf_len > 0)
    control_url = gaim_upnp_parse_description_response (dd->buf,
                                                        dd->buf_len,
                                                        dd->full_url,
                                                        dd->service_type);
  control_info.status = control_url ? GAIM_UPNP_STATUS_DISCOVERED
    : GAIM_UPNP_STATUS_UNABLE_TO_DISCOVER;
  GNUNET_free_non_null (control_info.control_url);
  control_info.control_url = control_url;
  control_info.service_type = dd->service_type;
  return len;
}

static int
gaim_upnp_parse_description (char *proxy, UPnPDiscoveryData * dd)
{
  CURL *curl;
  int ret;

  if (0 != curl_global_init (CURL_GLOBAL_WIN32))
    return GNUNET_SYSERR;
  curl = curl_easy_init ();
  setup_curl (proxy, curl);
  ret = CURLE_OK;
  CURL_EASY_SETOPT (curl, CURLOPT_URL, dd->full_url);
  CURL_EASY_SETOPT (curl, CURLOPT_WRITEFUNCTION, &upnp_parse_description_cb);
  CURL_EASY_SETOPT (curl, CURLOPT_WRITEDATA, dd);
  CURL_EASY_SETOPT (curl, CURLOPT_MAXREDIRS, 1L);
  CURL_EASY_SETOPT (curl, CURLOPT_CONNECTTIMEOUT, 1L);
  CURL_EASY_SETOPT (curl, CURLOPT_TIMEOUT, 2L);

  /* NOTE: use of CONNECTTIMEOUT without also
     setting NOSIGNAL results in really weird
     crashes on my system! */
  CURL_EASY_SETOPT (curl, CURLOPT_NOSIGNAL, 1);
  ret = curl_easy_perform (curl);
  if (ret != CURLE_OK)
    GNUNET_GE_LOG (NULL,
                   GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_DEVELOPER |
                   GNUNET_GE_BULK, _("%s failed at %s:%d: `%s'\n"),
                   "curl_easy_perform", __FILE__, __LINE__,
                   curl_easy_strerror (ret));
  curl_easy_cleanup (curl);
  curl_global_cleanup ();
  if (control_info.control_url == NULL)
    return GNUNET_SYSERR;
  return GNUNET_OK;
}

int
gaim_upnp_discover (struct GNUNET_GE_Context *ectx,
                    struct GNUNET_GC_Configuration *cfg, int sock)
{
  char *proxy;
  socklen_t avail;
  struct sockaddr_in server;
  int retry_count;
  char *sendMessage;
  size_t totalSize;
  int sentSuccess;
  char buf[65536];
  int buf_len;
  const char *startDescURL;
  const char *endDescURL;
  int ret;
  UPnPDiscoveryData dd;
  struct sockaddr *sa;

  memset (&dd, 0, sizeof (UPnPDiscoveryData));
  if (control_info.status == GAIM_UPNP_STATUS_DISCOVERING)
    return GNUNET_NO;
  dd.sock = sock;
  memset (&server, 0, sizeof (struct sockaddr_in));
  server.sin_family = AF_INET;
  avail = sizeof (struct sockaddr_in);
  sa = (struct sockaddr *) &server;
  if (GNUNET_OK !=
      GNUNET_get_ip_from_hostname (ectx,
                                   HTTPMU_HOST_ADDRESS, AF_INET, &sa, &avail))
    {
      return GNUNET_SYSERR;
    }
  server.sin_port = htons (HTTPMU_HOST_PORT);
  control_info.status = GAIM_UPNP_STATUS_DISCOVERING;

  /* because we are sending over UDP, if there is a failure
     we should retry the send NUM_UDP_ATTEMPTS times. Also,
     try different requests for WANIPConnection and WANPPPConnection */
  for (retry_count = 0; retry_count < NUM_UDP_ATTEMPTS; retry_count++)
    {
      sentSuccess = FALSE;
      if ((retry_count % 2) == 0)
        dd.service_type = WAN_IP_CONN_SERVICE;
      else
        dd.service_type = WAN_PPP_CONN_SERVICE;
      sendMessage = g_strdup_printf (SEARCH_REQUEST_STRING, dd.service_type);
      totalSize = strlen (sendMessage);
      do
        {
          if (SENDTO (dd.sock,
                      sendMessage,
                      totalSize,
                      0,
                      (struct sockaddr *) &server,
                      sizeof (struct sockaddr_in)) == totalSize)
            {
              sentSuccess = TRUE;
              break;
            }
        }
      while (((errno == EINTR) || (errno == EAGAIN)) &&
             (GNUNET_shutdown_test () == GNUNET_NO));
      GNUNET_free (sendMessage);
      if (sentSuccess)
        break;
    }
  if (sentSuccess == FALSE)
    return GNUNET_SYSERR;

  /* try to read response */
  do
    {
      buf_len = recv (dd.sock, buf, sizeof (buf) - 1, 0);
      if (buf_len > 0)
        {
          buf[buf_len] = '\0';
          break;
        }
      else if (errno != EINTR)
        {
          continue;
        }
    }
  while ((errno == EINTR) && (GNUNET_shutdown_test () == GNUNET_NO));

  /* parse the response, and see if it was a success */
  if (g_strstr_len (buf, buf_len, HTTP_OK) == NULL)
    return GNUNET_SYSERR;
  if ((startDescURL = g_strstr_len (buf, buf_len, "http://")) == NULL)
    return GNUNET_SYSERR;

  endDescURL = g_strstr_len (startDescURL,
                             buf_len - (startDescURL - buf), "\r");
  if (endDescURL == NULL)
    endDescURL = g_strstr_len (startDescURL,
                               buf_len - (startDescURL - buf), "\n");
  if (endDescURL == NULL)
    return GNUNET_SYSERR;
  if (endDescURL == startDescURL)
    return GNUNET_SYSERR;
  dd.full_url = GNUNET_strdup (startDescURL);
  dd.full_url[endDescURL - startDescURL] = '\0';
  proxy = NULL;
  GNUNET_GC_get_configuration_value_string (cfg,
                                            "GNUNETD", "HTTP-PROXY", "",
                                            &proxy);
  ret = gaim_upnp_parse_description (proxy, &dd);
  GNUNET_free (dd.full_url);
  GNUNET_array_grow (dd.buf, dd.buf_len, 0);
  if (ret == GNUNET_OK)
    {
      ret = gaim_upnp_generate_action_message_and_send (proxy,
                                                        "GetExternalIPAddress",
                                                        "",
                                                        looked_up_public_ip_cb,
                                                        &dd);
      GNUNET_array_grow (dd.buf, dd.buf_len, 0);
    }
  GNUNET_free (proxy);
  return ret;
}

const char *
gaim_upnp_get_public_ip ()
{
  if ((control_info.status == GAIM_UPNP_STATUS_DISCOVERED)
      && (strlen (control_info.publicip) > 0))
    return control_info.publicip;
  return NULL;
}

int
gaim_upnp_change_port_mapping (struct GNUNET_GE_Context *ectx,
                               struct GNUNET_GC_Configuration *cfg,
                               int do_add,
                               unsigned short portmap, const char *protocol)
{
  const char *action_name;
  char *action_params;
  char *internal_ip;
  char *proxy;
  int ret;

  if (control_info.status != GAIM_UPNP_STATUS_DISCOVERED)
    return GNUNET_NO;
  if (do_add)
    {
      internal_ip = GNUNET_upnp_get_internal_ip (cfg, ectx);
      if (internal_ip == NULL)
        {
          gaim_debug_error ("upnp",
                            "gaim_upnp_set_port_mapping(): couldn't get local ip\n");
          return GNUNET_NO;
        }
      action_name = "AddPortMapping";
      action_params = g_strdup_printf (ADD_PORT_MAPPING_PARAMS,
                                       portmap,
                                       protocol, portmap, internal_ip);
      GNUNET_free (internal_ip);
    }
  else
    {
      action_name = "DeletePortMapping";
      action_params = g_strdup_printf (DELETE_PORT_MAPPING_PARAMS,
                                       portmap, protocol);
    }
  proxy = NULL;
  GNUNET_GC_get_configuration_value_string (cfg,
                                            "GNUNETD", "HTTP-PROXY", "",
                                            &proxy);
  ret =
    gaim_upnp_generate_action_message_and_send (proxy, action_name,
                                                action_params,
                                                &ignore_response, NULL);

  GNUNET_free (action_params);
  GNUNET_free (proxy);
  return ret;
}

/* end of upnp.c */

⌨️ 快捷键说明

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