From f9613c4dbc1bd6f6ebd81f015de42bb7ddb32141 Mon Sep 17 00:00:00 2001 From: Josh Elsasser Date: Fri, 20 Apr 2007 01:27:58 +0000 Subject: [PATCH] Quick hack to get some PPP UPnP devices working. --- libtransmission/upnp.c | 57 +++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/libtransmission/upnp.c b/libtransmission/upnp.c index 16ec8cea2..0d47642c3 100644 --- a/libtransmission/upnp.c +++ b/libtransmission/upnp.c @@ -30,7 +30,8 @@ #define SSDP_SUBTYPE "ssdp:alive" #define SSDP_FIRST_DELAY 3750 /* 3 3/4 seconds */ #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 LOOP_DETECT_THRESHOLD 10 /* error on 10 add/get/del state changes */ #define MAPPING_CHECK_INTERVAL 900000 /* 15 minutes */ @@ -45,7 +46,6 @@ typedef struct tr_upnp_action_s { char * name; - char * action; int len; struct { char * name; char * var; char dir; } * args; } tr_upnp_action_t; @@ -56,6 +56,7 @@ typedef struct tr_upnp_device_s char * host; char * root; int port; + int ppp; char * soap; char * scpd; int mappedport; @@ -122,7 +123,7 @@ static tr_http_t * devicePulseGetHttp( tr_upnp_device_t * dev ); static int parseRoot( const char * root, const char *buf, int len, - char ** soap, char ** scpd ); + char ** soap, char ** scpd, int * ppp ); static void addUrlbase( const char * base, char ** path ); static int @@ -137,7 +138,7 @@ static char * joinstrs( const char *, const char *, const char * ); static tr_http_t * 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 actionSetup( tr_upnp_action_t * action, const char * name, int prealloc ); static void @@ -673,7 +674,7 @@ devicePulse( tr_upnp_device_t * dev, int port ) dev->host, code ); } 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 ); } @@ -822,7 +823,8 @@ static tr_http_t * devicePulseGetHttp( tr_upnp_device_t * dev ) { tr_http_t * ret; - char numstr[6]; + char numstr[6]; + const char * type; ret = NULL; switch( dev->state ) @@ -846,8 +848,9 @@ devicePulseGetHttp( tr_upnp_device_t * dev ) break; } 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, - &dev->addcmd, + type, &dev->addcmd, "PortMappingEnabled", "1", "PortMappingLeaseDuration", "0", "RemoteHost", "", @@ -860,8 +863,9 @@ devicePulseGetHttp( tr_upnp_device_t * dev ) break; case UPNPDEV_STATE_GET: 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, - &dev->getcmd, + type, &dev->getcmd, "RemoteHost", "", "ExternalPort", numstr, "PortMappingProtocol", "TCP", @@ -869,8 +873,9 @@ devicePulseGetHttp( tr_upnp_device_t * dev ) break; case UPNPDEV_STATE_DEL: 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, - &dev->delcmd, + type, &dev->delcmd, "RemoteHost", "", "ExternalPort", numstr, "PortMappingProtocol", "TCP", @@ -951,7 +956,7 @@ devicePulseHttp( tr_upnp_device_t * dev, static int 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; char * basedup; @@ -998,10 +1003,21 @@ parseRoot( const char * root, const char *buf, int len, kk = tr_xmlFindTag( kk, end, "service" ); buf = tr_xmlTagContents( kk, end ); if( !tr_xmlFindTagVerifyContents( buf, end, "serviceType", - UPNP_SERVICE_TYPE, 1 ) ) + SERVICE_TYPE_IP, 1 ) ) { *soap = tr_xmlDupTagContents( buf, end, "controlURL"); *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; } } @@ -1207,12 +1223,13 @@ joinstrs( const char * first, const char * delim, const char * second ) static tr_http_t * 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; va_list ap; const char * name, * value; int method; + char * actstr; method = ( retry ? TR_HTTP_M_POST : TR_HTTP_POST ); 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", "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 ) { 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 "\"" " s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" " " -" ", action->name ); +" ", action->name, type ); va_start( ap, action ); do @@ -1270,8 +1290,6 @@ static void actionSetup( tr_upnp_action_t * action, const char * name, int prealloc ) { action->name = strdup( name ); - action->action = NULL; - asprintf( &action->action, "\"%s#%s\"", UPNP_SERVICE_TYPE, name ); assert( NULL == action->args ); action->args = malloc( sizeof( *action->args ) * prealloc ); memset( action->args, 0, sizeof( *action->args ) * prealloc ); @@ -1282,7 +1300,6 @@ static void actionFree( tr_upnp_action_t * act ) { free( act->name ); - free( act->action ); while( 0 < act->len ) { act->len--; @@ -1369,7 +1386,7 @@ main( int argc, char * argv[] ) { struct stat sb; char * data, * soap, * scpd; - int fd; + int fd, ppp; ssize_t res; if( 3 != argc ) @@ -1414,13 +1431,13 @@ main( int argc, char * argv[] ) 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" ); } 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( scpd ); }