📄 upnp.c
字号:
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 + -