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
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 :-)
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 =