Interpret two styles of IGD response, deal with XML changes.

pull/206/head
dannybackx 8 years ago
parent b8fd2b8ec4
commit 812263aa42
  1. 117
      esp-link/upnp.c

@ -46,6 +46,13 @@ enum upnp_state_t {
};
static enum upnp_state_t upnp_state;
enum service_type_t {
service_type_unknown,
wanppp,
wanip
};
static enum service_type_t service_type = service_type_unknown;
/*
* Query #1 : SSDP protocol, this is a UDP multicast to discover a IGD device.
* (internet gateway device)
@ -61,6 +68,14 @@ static int ssdp_len;
static char *control_url = 0;
static int counter;
static const char *service_type_wanip = "urn:upnp-org:serviceId:WANIPConn1";
static int service_type_wanip_len = 33;
static const char *service_type_wanppp = "urn:upnp-org:serviceId:WANPPPConn1";
static int service_type_wanppp_len = 34;
static const char *connection_wanppp = "WANPPPConnection";
static const char *connection_wanip = "WANIPConnection";
/*
* Query #2 : query the IGD for its device & service list.
* We search this list for the control URL of the router.
@ -85,7 +100,9 @@ static const char *upnp_query_external_address =
"User-Agent: esp-link\r\n"
"Content-Length : %d\r\n" // XML length
"Content-Type: text/xml\r\n"
"SOAPAction: \"urn:schemas-upnp-org:service:WANPPPConnection:1#GetExternalIPAddress\"\r\n"
// "SOAPAction: \"urn:schemas-upnp-org:service:WANPPPConnection:1#GetExternalIPAddress\"\r\n"
"SOAPAction: \"urn:schemas-upnp-org:service:%s:1#GetExternalIPAddress\"\r\n"
// WANPPPConnection
"Connection: Close\r\n"
"Cache-Control: no-cache\r\n"
"Pragma: no-cache\r\n"
@ -95,7 +112,8 @@ static const char *upnp_query_external_address_xml =
"<?xml version=\"1.0\"?>\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:GetExternalIPAddress xmlns:u=\"urn:schemas-upnp-org:service:WANPPPConnection:1\">\r\n"
// "<u:GetExternalIPAddress xmlns:u=\"urn:schemas-upnp-org:service:WANPPPConnection:1\">\r\n"
"<u:GetExternalIPAddress xmlns:u=\"urn:schemas-upnp-org:service:%s:1\">\r\n"
"</u:GetExternalIPAddress>\r\n"
"</s:Body>\r\n"
"</s:Envelope>\r\n";
@ -141,7 +159,8 @@ static const char *upnp_query_add_tmpl =
"User-Agent: esp-link\r\n"
"Content-Length: %d\r\n" // Length of XML
"Content-Type: text/xml\r\n"
"SOAPAction: \"urn:schemas-upnp-org:service:WANPPPConnection:1#AddPortMapping\"\r\n"
// "SOAPAction: \"urn:schemas-upnp-org:service:WANPPPConnection:1#AddPortMapping\"\r\n"
"SOAPAction: \"urn:schemas-upnp-org:service:%s:1#AddPortMapping\"\r\n"
"Connection: Close\r\n"
"Cache-Control: no-cache\r\n"
"Pragma: no-cache\r\n\r\n%s"; // XML
@ -151,7 +170,8 @@ static const char *upnp_query_add_xml =
"<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:AddPortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANPPPConnection:1\">\r\n"
// "<u:AddPortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANPPPConnection:1\">\r\n"
"<u:AddPortMapping xmlns:u=\"urn:schemas-upnp-org:service:%s:1\">\r\n"
"<NewRemoteHost></NewRemoteHost>\r\n"
"<NewExternalPort>%d</NewExternalPort>\r\n" // remote port
"<NewProtocol>TCP</NewProtocol>\r\n"
@ -361,6 +381,7 @@ ssdp_sent_cb(void *arg) {
*/
static void ICACHE_FLASH_ATTR upnp_query_igd(UPnPClient *client) {
char *query, *xml;
char *p, *q;
// Create new espconn
client->con = (struct espconn *)os_zalloc(sizeof(struct espconn));
@ -396,29 +417,42 @@ static void ICACHE_FLASH_ATTR upnp_query_igd(UPnPClient *client) {
os_printf("Port to be added is %08x : %04x (remote %04x)\n", client->ip.addr, client->port, client->remote_port);
// Two step approach, as the XML also contains variable info, and we need to pass its length.
xml = (char *)os_malloc(strlen(upnp_query_add_xml) + 32);
xml = (char *)os_malloc(strlen(upnp_query_add_xml) + strlen(connection_wanppp) + 32);
// FIXME byte order issue ?
os_sprintf(xml, upnp_query_add_xml, client->remote_port, client->port,
ip4_addr4(&client->ip), ip4_addr3(&client->ip),
ip4_addr2(&client->ip), ip4_addr1(&client->ip));
os_sprintf(xml, upnp_query_add_xml,
(service_type == wanppp) ? connection_wanppp : connection_wanip,
client->remote_port, client->port,
ip4_addr1(&client->ip), ip4_addr2(&client->ip),
ip4_addr3(&client->ip), ip4_addr4(&client->ip));
// os_printf("XML %s\n", xml);
// os_printf("Control URL %s\n", client->control_url);
// return; // Danny
// Step 2 : create the headers.
query = (char *)os_malloc(strlen(upnp_query_add_tmpl) + strlen(client->control_url) + strlen(client->host) + 10 + strlen(xml));
os_sprintf(query, upnp_query_add_tmpl,
client->control_url, client->host,
strlen(xml), xml);
strlen(xml),
(service_type == wanppp) ? connection_wanppp : connection_wanip,
xml);
// Don't forget to free the temporary string storage for step 1.
os_free(xml);
#if 1
// os_printf("QUERY %s\n", query);
// os_printf("Control URL %s\n", client->control_url);
// return; // Danny
#if 0
// Production : no debug output
break;
#else
//os_printf("Query : %s\n", query);
// Just calling os_printf() produces empty lines (\r\n)
char *p, *q;
os_printf("Query : ");
for (p=query; *p; p++) {
for (q=p; *q && *q != '\r'; q++) ;
*q = 0;
@ -426,6 +460,7 @@ static void ICACHE_FLASH_ATTR upnp_query_igd(UPnPClient *client) {
*q = '\r';
p=q+1;
}
// return; // Danny
break;
#endif
@ -456,7 +491,6 @@ static void ICACHE_FLASH_ATTR upnp_query_igd(UPnPClient *client) {
#else
//os_printf("Query : %s\n", query);
// Just calling os_printf() produces empty lines (\r\n)
char *p, *q;
for (p=query; *p; p++) {
for (q=p; *q && *q != '\r'; q++) ;
*q = 0;
@ -468,12 +502,21 @@ static void ICACHE_FLASH_ATTR upnp_query_igd(UPnPClient *client) {
#endif
case upnp_query_extaddress:
// Step 1
xml = os_malloc(strlen(upnp_query_external_address_xml) + strlen(connection_wanppp));
os_sprintf(xml, upnp_query_external_address_xml,
(service_type == wanppp) ? connection_wanppp : connection_wanip);
// Step 2
query = os_malloc(strlen(upnp_query_external_address) + strlen(the_client->control_url) +
strlen(the_client->host) + 8 + strlen(upnp_query_external_address_xml));
strlen(the_client->host) + 8 + strlen(xml) + strlen(connection_wanppp));
os_sprintf(query, upnp_query_external_address,
the_client->control_url, the_client->host,
strlen(upnp_query_external_address_xml), upnp_query_external_address_xml);
#if 1
strlen(xml),
(service_type == wanppp) ? connection_wanppp : connection_wanip,
xml);
os_free(xml);
#if 0
// Production : no debug output
break;
#else
@ -555,6 +598,7 @@ upnp_tcp_discon_cb(void *arg) {
// Kick SM into next state, trigger next query
switch (upnp_state) {
case upnp_found_igd:
os_printf("upnp_tcp_discon_cb set state to READY\n");
upnp_state = upnp_ready;
break;
@ -641,12 +685,34 @@ upnp_tcp_recv_cb(void *arg, char *pdata, unsigned short len) {
case upnp_found_igd:
// Find a service with specific id, remember its control-url.
for (int i=0; i<len; i++) {
// Debug
if (strncasecmp(pdata+i, "<serviceType>", 13) == 0) {
int k, l;
for (k=i+13; pdata[k] && pdata[k] != '<'; k++) ;
for (l=i; l<k; l++)
os_printf("%c", pdata[l]);
os_printf("\n");
}
// End debug
if (strncasecmp(pdata+i, "<service>", 9) == 0) {
inservice++;
#if 0
// Debug
int k, l;
for (k=i, l=0; l<4 && k<i+500; k++) {
if (pdata[k] == '\n') l++;
os_printf("%c", pdata[k]);
}
#endif
} else if (strncasecmp(pdata+i, "</service>", 10) == 0) {
inservice--;
} else if (strncasecmp(pdata+i, "urn:upnp-org:serviceId:WANPPPConn1", 34) == 0) {
} else if (strncasecmp(pdata+i, service_type_wanip, service_type_wanip_len) == 0) {
get_this = inservice;
service_type = wanip;
} else if (strncasecmp(pdata+i, service_type_wanppp, service_type_wanppp_len) == 0) {
get_this = inservice;
service_type = wanppp;
} else if (get_this == inservice && strncasecmp(pdata+i, "<controlURL>", 12) == 0) {
get_this = -1;
int j;
@ -669,9 +735,9 @@ upnp_tcp_recv_cb(void *arg, char *pdata, unsigned short len) {
case upnp_ready:
break;
case upnp_adding_port:
// FIXME
// os_printf("UPnP <adding port> TCP Recv len %d, %s\n", len, pdata);
os_printf("UPnP <adding port> TCP Recv len %d\n", len);
// FIXME should interpret the result
break;
case upnp_removing_port:
// FIXME
@ -710,6 +776,14 @@ void ICACHE_FLASH_ATTR
cmdUPnPScan(CmdPacket *cmd) {
os_printf("cmdUPnPScan()\n");
// States that signify we're not ready --> reply immediately, with NULL
if (upnp_state == upnp_multicasted || upnp_state == upnp_found_igd) {
cmdResponseStart(CMD_RESP_V, 0, 0);
cmdResponseEnd();
return;
}
// If we're ready, return indicating the IP address of the router
if (upnp_state == upnp_ready) {
// Return the IP address of the gateway, this indicates success.
if (the_client == 0)
@ -720,6 +794,7 @@ cmdUPnPScan(CmdPacket *cmd) {
return;
}
// Otherwise, start a scan already
upnp_state = upnp_none;
struct espconn *con = (struct espconn *)os_zalloc(sizeof(struct espconn));
@ -835,6 +910,14 @@ cmdUPnPAddPort(CmdPacket *cmd) {
the_client->port = local_port;
the_client->remote_port = remote_port;
#if 0
// Stop right here
// Return 0 -> ok
cmdResponseStart(CMD_RESP_V, 0, 0);
cmdResponseEnd();
return;
#endif
upnp_state = upnp_adding_port;
upnp_query_igd(the_client);

Loading…
Cancel
Save