#13 Host+Port missing on POST from AddPortMapping action

open
Satoshi Konno
None
5
2004-03-16
2004-03-02
Paul Gardner
No

I'm trying to write some code to register a port mapping
for Azureus (http://azureus.sourceforge.net/).

My code looks like this:

Debug.on();

final ControlPoint ctrlPoint = new ControlPoint();

ctrlPoint.start();

SearchResponseListener listener =
new SearchResponseListener()
{
public void

deviceSearchResponseReceived(SSDPPacket
packet)
{

System.out.println
(packet.getUSN() + " - " + packet.getST() + " - " +
packet.getLocation());

ctrlPoint.print();

processDevices
( "", ctrlPoint.getDeviceList());
}
};

ctrlPoint.addSearchResponseListener(listener);

//ctrlPoint.search("upnp:rootdevice");

ctrlPoint.search( "urn:schemas-upnp-
org:service:WANIPConnection:1" );

}

// ctrlPoint.stop();
//ctrlPoint.finalize();

protected static void
processDevices(
String indent,
DeviceList devices )
{
for(int i =0 ; i < devices.size() ; i++){

Device dev =
devices.getDevice(i);

String devType =
dev.getDeviceType();

System.out.println
(indent+"device type:" + devType );

ServiceList services =
dev.getServiceList();

for( int j=0 ; j <
services.size() ; j++) {

Service service =
services.getService(j);

String serviceType
= service.getServiceType();

System.out.println
(indent+" - Found service : "+ serviceType );

List action_list =
service.getActionList();

for (int
k=0;k<action_list.size();k++){

Action
action = (Action)action_list.get(k);

System.out.println( indent + " - action = " +
action.getName());

if (
action.getName().equals( "AddPortMapping" )){

ArgumentList args =
action.getInputArgumentList();

for (int z=0;z<args.size();z++){

Argument arg = args.getArgument(z);

System.out.println( "arg=" + arg.getName()
+ "/" + arg.getValue());

}

//action.setArgumentValue
("NewRemoteHost","");

action.setArgumentValue("NewExternalPort",7007);

action.setArgumentValue("NewProtocol","TCP");

action.setArgumentValue("NewInternalPort",7007);

action.setArgumentValue
("NewInternalClient","192.168.0.2");

action.setArgumentValue("NewEnabled",1);

action.setArgumentValue
("NewPortMappingDescription","AZTest");

action.setArgumentValue("NewLeaseDuration",9999);

action.setActionListener(

new ActionListener()

{

public boolean

actionControlReceived(

Action action )

{

System.out.println( "control
received" );

return( true );

}

});

System.out.println(action.postControlAction());

UPnPStatus
status = action.getStatus();

System.out.println( "status = " + status.getDescription
());

System.exit
(0);
}
}
}

DeviceList
sub_devs = dev.getDeviceList();

processDevices( indent
+ " ", sub_devs );

/*

if(serviceType.equals("WANIPConnection:1") ||
serviceType.equals("WANPPPConnection:1")) {

System.out.println("Found a WANIP or WANPPP
Connection");

}
*/
}
}

So I basically drill down the device hierarchy looking for
the AddPortMapping action and then call it.

However, the URL used to send the action to on my
router appears to be blank: tracing shows:

POST /upnp/control/WANIPConnection HTTP/1.0
CONTENT-TYPE: text/xml; charset="utf-8"
HOST: :80
CONTENT-LENGTH: 645
SOAPACTION: "urn:schemas-upnp-
org:service:WANIPConnection:1#AddPortMapping"

<?xml version="1.0"?>
<s:Envelope
xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
s:encodingStyle="http://schemas.xmlsoap.org/soap/enco
ding/">
<s:Body>
<u:AddPortMapping
xmlns:u="urn:schemas-upnp-
org:service:WANIPConnection:1">

<NewRemoteHost></NewRemoteHost>

<NewExternalPort>7007</NewExternalPort>

<NewProtocol>TCP</NewProtocol>

<NewInternalPort>7007</NewInternalPort>

<NewInternalClient>192.168.0.2</NewInternalCl
ient>

<NewEnabled>1</NewEnabled>

<NewPortMappingDescription>AZTest</NewPort
MappingDescription>

<NewLeaseDuration>9999</NewLeaseDuration>
</u:AddPortMapping>
</s:Body>
</s:Envelope>

postMessge: host = , port = 80
HTTP/1.0 200
CONTENT-TYPE: text/xml; charset="utf-8"
SERVER: AV/1.0.1
CONTENT-LENGTH: 0
Mime-version: 1.0
EXT:

<s:Envelope
xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
s:encodingStyle="http://schemas.xmlsoap.org/soap/enco
ding/">
<s:Body></s:Body>
</s:Envelope>

So the HOST is missing (and the port).

When I hardcode the correct values into
ControlRequest.java:

protected void setRequestHost(Service service)
{
String ctrlURL = service.getControlURL
();

// Thanks for Giordano Sassaroli
<sassarol@cefriel.it> (05/21/03)
setURI(ctrlURL, true);

Device rootDev =
service.getRootDevice();

String urlBaseStr =
rootDev.getURLBase();
// Thanks for Giordano Sassaroli
<sassarol@cefriel.it> and Suzan Foster (09/02/03)
if (urlBaseStr == null ||
urlBaseStr.length() <= 0) {
if (HTTP.isAbsoluteURL
(ctrlURL))
urlBaseStr =
ctrlURL;
}
String reqHost = "192.168.0.1"; //
PARG HTTP.getHost(urlBaseStr);
int reqPort = 49152; // HTTP.getPort
(urlBaseStr);

setHost(reqHost, reqPort);
setRequestHost(reqHost);
setRequestPort(reqPort);
}

It works OK.

Any ideas? And is there a better way to do this?!?!

thanks and gambatte!
Paul

Discussion

  • Satoshi Konno
    Satoshi Konno
    2004-03-16

    • assigned_to: nobody --> skonno
     
  • Satoshi Konno
    Satoshi Konno
    2004-03-17

    Logged In: YES
    user_id=559351

    Hi Paul,

    I don't know about your router, but I seem that your can set
    the action with the latest CyberLink becuse the CyberLink
    can get the ipaddress and the port from the SSDP packect
    when the URLBase is null and the control URL is not absolute
    from v1.3.2. The implementation is bellow.

    protected void setRequestHost(Service service)
    {
    String ctrlURL = service.getControlURL();

    // Thanks for Giordano Sassaroli
    <sassarol@cefriel.it> (05/21/03)
    setURI(ctrlURL, true);

    // Thanks for Giordano Sassaroli
    <sassarol@cefriel.it> and Suzan Foster (09/02/03)
    // Thanks for Andre <andre@antiheld.net>
    (02/18/04)
    String urlBaseStr = "";
    if (HTTP.isAbsoluteURL(ctrlURL) == true)
    urlBaseStr = ctrlURL;

    if (urlBaseStr == null || urlBaseStr.length()
    <= 0)
    urlBaseStr =
    service.getRootDevice().getURLBase();

    // Thanks for Rob van den Boomen
    <rob.van.den.boomen@philips.com> (02/17/04)
    // BUGFIX, set urlbase from location string
    if not set in description.xml
    if (urlBaseStr == null || urlBaseStr.length()
    <= 0)
    urlBaseStr =
    service.getRootDevice().getLocation();

    String reqHost = HTTP.getHost
    (urlBaseStr);
    int reqPort = HTTP.getPort(urlBaseStr);

    setHost(reqHost, reqPort);
    setRequestHost(reqHost);
    setRequestPort(reqPort);
    }

    Please check it :-)

     
  • Paul Gardner
    Paul Gardner
    2004-03-17

    Logged In: YES
    user_id=866182

    Sorry, should have said that the router is a NETGEAR DG834G.

    Nearly works! What's missing now is the HTTP version number
    from the end of the request - you can see below that it ends
    with "HTTP/" instead of "HTTP/1.0":

    POST /upnp/control/WANIPConnection HTTP/
    CONTENT-TYPE: text/xml; charset="utf-8"
    HOST: 192.168.0.1:49153
    CONTENT-LENGTH: 645
    SOAPACTION: "urn:schemas-upnp-
    org:service:WANIPConnection:1#AddPortMapping"

    <?xml version="1.0"?>
    <s:Envelope
    xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
    s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
    >
    <s:Body>
    <u:AddPortMapping xmlns:u="urn:schemas-
    upnp-org:service:WANIPConnection:1">

    <NewRemoteHost></NewRemoteHost>

    <NewExternalPort>7007</NewExternalPort>

    <NewProtocol>TCP</NewProtocol>

    <NewInternalPort>7007</NewInternalPort>

    <NewInternalClient>192.168.0.2</NewInternalClient>
    <NewEnabled>1</NewEnabled>

    <NewPortMappingDescription>AZTest</NewPortMappi
    ngDescription>

    <NewLeaseDuration>9999</NewLeaseDuration>
    </u:AddPortMapping>
    </s:Body>
    </s:Envelope>

    HTTP/1.0 400
    CONTENT-TYPE: text/xml; charset="utf-8"
    SERVER: Linux/2.4.17_mvl21-malta-mips_fp_le, UPnP/1.0,
    Intel SDK for UPnP devices /1.2
    CONTENT-LENGTH: 50
    EXT:

    <html><body><h1>400 Bad Request</h1></body></html>
    false
    status =