mirror of
https://github.com/transmission/transmission
synced 2024-12-25 01:03:01 +00:00
Quick hack to get some PPP UPnP devices working.
This commit is contained in:
parent
312fe89d7b
commit
f9613c4dbc
1 changed files with 37 additions and 20 deletions
|
@ -30,7 +30,8 @@
|
||||||
#define SSDP_SUBTYPE "ssdp:alive"
|
#define SSDP_SUBTYPE "ssdp:alive"
|
||||||
#define SSDP_FIRST_DELAY 3750 /* 3 3/4 seconds */
|
#define SSDP_FIRST_DELAY 3750 /* 3 3/4 seconds */
|
||||||
#define SSDP_MAX_DELAY 1800000 /* 30 minutes */
|
#define SSDP_MAX_DELAY 1800000 /* 30 minutes */
|
||||||
#define UPNP_SERVICE_TYPE "urn:schemas-upnp-org:service:WANIPConnection:1"
|
#define SERVICE_TYPE_IP "urn:schemas-upnp-org:service:WANIPConnection:1"
|
||||||
|
#define SERVICE_TYPE_PPP "urn:schemas-upnp-org:service:WANPPPConnection:1"
|
||||||
#define SOAP_ENVELOPE "http://schemas.xmlsoap.org/soap/envelope/"
|
#define SOAP_ENVELOPE "http://schemas.xmlsoap.org/soap/envelope/"
|
||||||
#define LOOP_DETECT_THRESHOLD 10 /* error on 10 add/get/del state changes */
|
#define LOOP_DETECT_THRESHOLD 10 /* error on 10 add/get/del state changes */
|
||||||
#define MAPPING_CHECK_INTERVAL 900000 /* 15 minutes */
|
#define MAPPING_CHECK_INTERVAL 900000 /* 15 minutes */
|
||||||
|
@ -45,7 +46,6 @@
|
||||||
typedef struct tr_upnp_action_s
|
typedef struct tr_upnp_action_s
|
||||||
{
|
{
|
||||||
char * name;
|
char * name;
|
||||||
char * action;
|
|
||||||
int len;
|
int len;
|
||||||
struct { char * name; char * var; char dir; } * args;
|
struct { char * name; char * var; char dir; } * args;
|
||||||
} tr_upnp_action_t;
|
} tr_upnp_action_t;
|
||||||
|
@ -56,6 +56,7 @@ typedef struct tr_upnp_device_s
|
||||||
char * host;
|
char * host;
|
||||||
char * root;
|
char * root;
|
||||||
int port;
|
int port;
|
||||||
|
int ppp;
|
||||||
char * soap;
|
char * soap;
|
||||||
char * scpd;
|
char * scpd;
|
||||||
int mappedport;
|
int mappedport;
|
||||||
|
@ -122,7 +123,7 @@ static tr_http_t *
|
||||||
devicePulseGetHttp( tr_upnp_device_t * dev );
|
devicePulseGetHttp( tr_upnp_device_t * dev );
|
||||||
static int
|
static int
|
||||||
parseRoot( const char * root, const char *buf, int len,
|
parseRoot( const char * root, const char *buf, int len,
|
||||||
char ** soap, char ** scpd );
|
char ** soap, char ** scpd, int * ppp );
|
||||||
static void
|
static void
|
||||||
addUrlbase( const char * base, char ** path );
|
addUrlbase( const char * base, char ** path );
|
||||||
static int
|
static int
|
||||||
|
@ -137,7 +138,7 @@ static char *
|
||||||
joinstrs( const char *, const char *, const char * );
|
joinstrs( const char *, const char *, const char * );
|
||||||
static tr_http_t *
|
static tr_http_t *
|
||||||
soapRequest( int retry, const char * host, int port, const char * path,
|
soapRequest( int retry, const char * host, int port, const char * path,
|
||||||
tr_upnp_action_t * action, ... );
|
const char * type, tr_upnp_action_t * action, ... );
|
||||||
static void
|
static void
|
||||||
actionSetup( tr_upnp_action_t * action, const char * name, int prealloc );
|
actionSetup( tr_upnp_action_t * action, const char * name, int prealloc );
|
||||||
static void
|
static void
|
||||||
|
@ -673,7 +674,7 @@ devicePulse( tr_upnp_device_t * dev, int port )
|
||||||
dev->host, code );
|
dev->host, code );
|
||||||
}
|
}
|
||||||
else if( parseRoot( dev->root, body, len,
|
else if( parseRoot( dev->root, body, len,
|
||||||
&dev->soap, &dev->scpd ) )
|
&dev->soap, &dev->scpd, &dev->ppp ) )
|
||||||
{
|
{
|
||||||
tr_dbg( "upnp device %s: parse root failed", dev->host );
|
tr_dbg( "upnp device %s: parse root failed", dev->host );
|
||||||
}
|
}
|
||||||
|
@ -822,7 +823,8 @@ static tr_http_t *
|
||||||
devicePulseGetHttp( tr_upnp_device_t * dev )
|
devicePulseGetHttp( tr_upnp_device_t * dev )
|
||||||
{
|
{
|
||||||
tr_http_t * ret;
|
tr_http_t * ret;
|
||||||
char numstr[6];
|
char numstr[6];
|
||||||
|
const char * type;
|
||||||
|
|
||||||
ret = NULL;
|
ret = NULL;
|
||||||
switch( dev->state )
|
switch( dev->state )
|
||||||
|
@ -846,8 +848,9 @@ devicePulseGetHttp( tr_upnp_device_t * dev )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
snprintf( numstr, sizeof( numstr ), "%i", dev->mappedport );
|
snprintf( numstr, sizeof( numstr ), "%i", dev->mappedport );
|
||||||
|
type = ( dev->ppp ? SERVICE_TYPE_PPP : SERVICE_TYPE_IP );
|
||||||
ret = soapRequest( dev->soapretry, dev->host, dev->port, dev->soap,
|
ret = soapRequest( dev->soapretry, dev->host, dev->port, dev->soap,
|
||||||
&dev->addcmd,
|
type, &dev->addcmd,
|
||||||
"PortMappingEnabled", "1",
|
"PortMappingEnabled", "1",
|
||||||
"PortMappingLeaseDuration", "0",
|
"PortMappingLeaseDuration", "0",
|
||||||
"RemoteHost", "",
|
"RemoteHost", "",
|
||||||
|
@ -860,8 +863,9 @@ devicePulseGetHttp( tr_upnp_device_t * dev )
|
||||||
break;
|
break;
|
||||||
case UPNPDEV_STATE_GET:
|
case UPNPDEV_STATE_GET:
|
||||||
snprintf( numstr, sizeof( numstr ), "%i", dev->mappedport );
|
snprintf( numstr, sizeof( numstr ), "%i", dev->mappedport );
|
||||||
|
type = ( dev->ppp ? SERVICE_TYPE_PPP : SERVICE_TYPE_IP );
|
||||||
ret = soapRequest( dev->soapretry, dev->host, dev->port, dev->soap,
|
ret = soapRequest( dev->soapretry, dev->host, dev->port, dev->soap,
|
||||||
&dev->getcmd,
|
type, &dev->getcmd,
|
||||||
"RemoteHost", "",
|
"RemoteHost", "",
|
||||||
"ExternalPort", numstr,
|
"ExternalPort", numstr,
|
||||||
"PortMappingProtocol", "TCP",
|
"PortMappingProtocol", "TCP",
|
||||||
|
@ -869,8 +873,9 @@ devicePulseGetHttp( tr_upnp_device_t * dev )
|
||||||
break;
|
break;
|
||||||
case UPNPDEV_STATE_DEL:
|
case UPNPDEV_STATE_DEL:
|
||||||
snprintf( numstr, sizeof( numstr ), "%i", dev->mappedport );
|
snprintf( numstr, sizeof( numstr ), "%i", dev->mappedport );
|
||||||
|
type = ( dev->ppp ? SERVICE_TYPE_PPP : SERVICE_TYPE_IP );
|
||||||
ret = soapRequest( dev->soapretry, dev->host, dev->port, dev->soap,
|
ret = soapRequest( dev->soapretry, dev->host, dev->port, dev->soap,
|
||||||
&dev->delcmd,
|
type, &dev->delcmd,
|
||||||
"RemoteHost", "",
|
"RemoteHost", "",
|
||||||
"ExternalPort", numstr,
|
"ExternalPort", numstr,
|
||||||
"PortMappingProtocol", "TCP",
|
"PortMappingProtocol", "TCP",
|
||||||
|
@ -951,7 +956,7 @@ devicePulseHttp( tr_upnp_device_t * dev,
|
||||||
|
|
||||||
static int
|
static int
|
||||||
parseRoot( const char * root, const char *buf, int len,
|
parseRoot( const char * root, const char *buf, int len,
|
||||||
char ** soap, char ** scpd )
|
char ** soap, char ** scpd, int * ppp )
|
||||||
{
|
{
|
||||||
const char * end, * ii, * jj, * kk, * urlbase;
|
const char * end, * ii, * jj, * kk, * urlbase;
|
||||||
char * basedup;
|
char * basedup;
|
||||||
|
@ -998,10 +1003,21 @@ parseRoot( const char * root, const char *buf, int len,
|
||||||
kk = tr_xmlFindTag( kk, end, "service" );
|
kk = tr_xmlFindTag( kk, end, "service" );
|
||||||
buf = tr_xmlTagContents( kk, end );
|
buf = tr_xmlTagContents( kk, end );
|
||||||
if( !tr_xmlFindTagVerifyContents( buf, end, "serviceType",
|
if( !tr_xmlFindTagVerifyContents( buf, end, "serviceType",
|
||||||
UPNP_SERVICE_TYPE, 1 ) )
|
SERVICE_TYPE_IP, 1 ) )
|
||||||
{
|
{
|
||||||
*soap = tr_xmlDupTagContents( buf, end, "controlURL");
|
*soap = tr_xmlDupTagContents( buf, end, "controlURL");
|
||||||
*scpd = tr_xmlDupTagContents( buf, end, "SCPDURL");
|
*scpd = tr_xmlDupTagContents( buf, end, "SCPDURL");
|
||||||
|
*ppp = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* XXX we should save all services of both types and
|
||||||
|
try adding mappings for each in turn */
|
||||||
|
else if( !tr_xmlFindTagVerifyContents( buf, end, "serviceType",
|
||||||
|
SERVICE_TYPE_PPP, 1 ) )
|
||||||
|
{
|
||||||
|
*soap = tr_xmlDupTagContents( buf, end, "controlURL");
|
||||||
|
*scpd = tr_xmlDupTagContents( buf, end, "SCPDURL");
|
||||||
|
*ppp = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1207,12 +1223,13 @@ joinstrs( const char * first, const char * delim, const char * second )
|
||||||
|
|
||||||
static tr_http_t *
|
static tr_http_t *
|
||||||
soapRequest( int retry, const char * host, int port, const char * path,
|
soapRequest( int retry, const char * host, int port, const char * path,
|
||||||
tr_upnp_action_t * action, ... )
|
const char * type, tr_upnp_action_t * action, ... )
|
||||||
{
|
{
|
||||||
tr_http_t * http;
|
tr_http_t * http;
|
||||||
va_list ap;
|
va_list ap;
|
||||||
const char * name, * value;
|
const char * name, * value;
|
||||||
int method;
|
int method;
|
||||||
|
char * actstr;
|
||||||
|
|
||||||
method = ( retry ? TR_HTTP_M_POST : TR_HTTP_POST );
|
method = ( retry ? TR_HTTP_M_POST : TR_HTTP_POST );
|
||||||
http = makeHttp( method, host, port, path );
|
http = makeHttp( method, host, port, path );
|
||||||
|
@ -1220,7 +1237,10 @@ soapRequest( int retry, const char * host, int port, const char * path,
|
||||||
{
|
{
|
||||||
tr_httpAddHeader( http, "Content-type",
|
tr_httpAddHeader( http, "Content-type",
|
||||||
"text/xml; encoding=\"utf-8\"" );
|
"text/xml; encoding=\"utf-8\"" );
|
||||||
tr_httpAddHeader( http, "SOAPAction", action->action );
|
actstr = NULL;
|
||||||
|
asprintf( &actstr, "\"%s#%s\"", type, action->name );
|
||||||
|
tr_httpAddHeader( http, "SOAPAction", actstr );
|
||||||
|
free( actstr );
|
||||||
if( retry )
|
if( retry )
|
||||||
{
|
{
|
||||||
tr_httpAddHeader( http, "Man", "\"" SOAP_ENVELOPE "\"" );
|
tr_httpAddHeader( http, "Man", "\"" SOAP_ENVELOPE "\"" );
|
||||||
|
@ -1231,7 +1251,7 @@ soapRequest( int retry, const char * host, int port, const char * path,
|
||||||
" xmlns:s=\"" SOAP_ENVELOPE "\""
|
" xmlns:s=\"" SOAP_ENVELOPE "\""
|
||||||
" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
|
" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
|
||||||
" <s:Body>"
|
" <s:Body>"
|
||||||
" <u:%s xmlns:u=\"" UPNP_SERVICE_TYPE "\">", action->name );
|
" <u:%s xmlns:u=\%s\">", action->name, type );
|
||||||
|
|
||||||
va_start( ap, action );
|
va_start( ap, action );
|
||||||
do
|
do
|
||||||
|
@ -1270,8 +1290,6 @@ static void
|
||||||
actionSetup( tr_upnp_action_t * action, const char * name, int prealloc )
|
actionSetup( tr_upnp_action_t * action, const char * name, int prealloc )
|
||||||
{
|
{
|
||||||
action->name = strdup( name );
|
action->name = strdup( name );
|
||||||
action->action = NULL;
|
|
||||||
asprintf( &action->action, "\"%s#%s\"", UPNP_SERVICE_TYPE, name );
|
|
||||||
assert( NULL == action->args );
|
assert( NULL == action->args );
|
||||||
action->args = malloc( sizeof( *action->args ) * prealloc );
|
action->args = malloc( sizeof( *action->args ) * prealloc );
|
||||||
memset( action->args, 0, sizeof( *action->args ) * prealloc );
|
memset( action->args, 0, sizeof( *action->args ) * prealloc );
|
||||||
|
@ -1282,7 +1300,6 @@ static void
|
||||||
actionFree( tr_upnp_action_t * act )
|
actionFree( tr_upnp_action_t * act )
|
||||||
{
|
{
|
||||||
free( act->name );
|
free( act->name );
|
||||||
free( act->action );
|
|
||||||
while( 0 < act->len )
|
while( 0 < act->len )
|
||||||
{
|
{
|
||||||
act->len--;
|
act->len--;
|
||||||
|
@ -1369,7 +1386,7 @@ main( int argc, char * argv[] )
|
||||||
{
|
{
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
char * data, * soap, * scpd;
|
char * data, * soap, * scpd;
|
||||||
int fd;
|
int fd, ppp;
|
||||||
ssize_t res;
|
ssize_t res;
|
||||||
|
|
||||||
if( 3 != argc )
|
if( 3 != argc )
|
||||||
|
@ -1414,13 +1431,13 @@ main( int argc, char * argv[] )
|
||||||
|
|
||||||
close( fd );
|
close( fd );
|
||||||
|
|
||||||
if( parseRoot( argv[1], data, sb.st_size, &soap, &scpd ) )
|
if( parseRoot( argv[1], data, sb.st_size, &soap, &scpd, &ppp ) )
|
||||||
{
|
{
|
||||||
tr_err( "root parsing failed" );
|
tr_err( "root parsing failed" );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tr_err( "soap=%s scpd=%s", soap, scpd );
|
tr_err( "soap=%s scpd=%s ppp=%s", soap, scpd, ( ppp ? "yes" : "no" ) );
|
||||||
free( soap );
|
free( soap );
|
||||||
free( scpd );
|
free( scpd );
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue