/*
* Created on 14-Jun-2004
* Created by Paul Gardner
* Copyright (C) 2004, 2005, 2006 Aelitis, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* AELITIS, SAS au capital de 46,603.30 euros
* 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
*
*/
package com.aelitis.net.upnp.impl.ssdp;
import java.net.*;
import java.util.*;
import org.gudy.azureus2.core3.util.*;
import com.aelitis.net.upnp.*;
import com.aelitis.net.upnp.impl.*;
/**
* @author parg
*
*/
public class
SSDPIGDImpl
implements SSDPIGD, UPnPSSDPListener
{
private UPnPImpl upnp;
private SSDPCore ssdp_core;
private boolean first_result = true;
private long last_explicit_search = 0;
private List listeners = new ArrayList();
protected AEMonitor this_mon = new AEMonitor( "SSDP" );
public
SSDPIGDImpl(
UPnPImpl _upnp,
String[] _selected_interfaces )
throws UPnPException
{
upnp = _upnp;
ssdp_core =
SSDPCore.getSingleton(
upnp.getAdapter(),
UPnPSSDP.SSDP_GROUP_ADDRESS,
UPnPSSDP.SSDP_GROUP_PORT,
UPnPSSDP.SSDP_CONTROL_PORT,
_selected_interfaces );
ssdp_core.addListener( this );
}
public void
start()
throws UPnPException
{
try{
upnp.getAdapter().createThread(
"SSDP:queryLoop",
new AERunnable()
{
public void
runSupport()
{
queryLoop();
}
});
}catch( Throwable e ){
Debug.printStackTrace( e );
throw( new UPnPException( "Failed to initialise SSDP", e ));
}
}
public void
searchNow()
{
long now = SystemTime.getCurrentTime();
if ( now - last_explicit_search < 10000 ){
return;
}
last_explicit_search = now;
search();
}
protected void
queryLoop()
{
while(true){
try{
search();
Thread.sleep( 60000 );
}catch( Throwable e ){
Debug.printStackTrace( e );
}
}
}
protected void
search()
{
ssdp_core.search( "upnp:rootdevice" );
}
public void
receivedResult(
NetworkInterface network_interface,
InetAddress local_address,
InetAddress originator,
String usn,
URL location,
String st,
String al )
{
try{
this_mon.enter();
if ( st.equalsIgnoreCase( "upnp:rootdevice" )){
gotRoot( network_interface, local_address, usn, location );
}
}finally{
first_result = false;
this_mon.exit();
}
}
public void
receivedNotify(
NetworkInterface network_interface,
InetAddress local_address,
InetAddress originator,
String usn,
URL location,
String nt,
String nts )
{
try{
this_mon.enter();
if ( nt.indexOf( "upnp:rootdevice" ) != -1 ){
if ( nts.indexOf("alive") != -1 ){
// alive can be reported on any interface
try{
InetAddress dev = InetAddress.getByName( location.getHost());
byte[] dev_bytes = dev.getAddress();
boolean[] dev_bits = bytesToBits( dev_bytes );
// try and work out what bind address this location corresponds to
NetworkInterface best_ni = null;
InetAddress best_addr = null;
int best_prefix = 0;
Enumeration network_interfaces = NetworkInterface.getNetworkInterfaces();
while (network_interfaces.hasMoreElements()){
NetworkInterface this_ni = (NetworkInterface)network_interfaces.nextElement();
Enumeration ni_addresses = this_ni.getInetAddresses();
while (ni_addresses.hasMoreElements()){
InetAddress this_address = (InetAddress)ni_addresses.nextElement();
byte[] this_bytes = this_address.getAddress();
if ( dev_bytes.length == this_bytes.length ){
boolean[] this_bits = bytesToBits( this_bytes );
for (int i=0;i<this_bits.length;i++){
if ( dev_bits[i] != this_bits[i] ){
break;
}
if ( i > best_prefix ){
best_prefix = i;
best_ni = this_ni;
best_addr = this_address;
}
}
}
}
}
if ( best_ni != null ){
if ( first_result ){
upnp.log( location + " -> " + best_ni.getDisplayName() + "/" + best_addr + " (prefix=" + (best_prefix + 1 ) + ")");
}
gotRoot( best_ni, best_addr, usn, location );
}else{
gotAlive( usn, location );
}
}catch( Throwable e ){
gotAlive( usn, location );
}
}else if ( nts.indexOf( "byebye") != -1 ){
lostRoot( local_address, usn );
}
}
}finally{
first_result = false;
this_mon.exit();
}
}
public String[]
receivedSearch(
NetworkInterface network_interface,
InetAddress local_address,
InetAddress originator,
String ST )
{
// not interested, loopback or other search
return( null );
}
protected boolean[]
bytesToBits(
byte[] bytes )
{
boolean[] res = new boolean[bytes.length*8];
for (int i=0;i<bytes.length;i++){
byte b = bytes[i];
for (int j=0;j<8;j++){
res[i*8+j] = (b&(byte)(0x01<<(7-j))) != 0;
}
}
return( res );
}
protected void
gotRoot(
NetworkInterface network_interface,
InetAddress local_address,
String usn,
URL location )
{
for (int i=0;i<listeners.size();i++){
try{
((SSDPIGDListener)listeners.get(i)).rootDiscovered( network_interface, local_address, usn, location );
}catch( Throwable e ){
Debug.printStackTrace(e);
}
}
}
protected void
gotAlive(
String usn,
URL location )
{
for (int i=0;i<listeners.size();i++){
try{
((SSDPIGDListener)listeners.get(i)).rootAlive( usn, location );
}catch( Throwable e ){
Debug.printStackTrace(e);
}
}
}
protected void
lostRoot(
InetAddress local_address,
String usn )
{
for (int i=0;i<listeners.size();i++){
try{
((SSDPIGDListener)listeners.get(i)).rootLost( local_address, usn );
}catch( Throwable e ){
Debug.printStackTrace(e);
}
}
}
public void
interfaceChanged(
NetworkInterface network_interface )
{
for (int i=0;i<listeners.size();i++){
try{
((SSDPIGDListener)listeners.get(i)).interfaceChanged( network_interface );
}catch( Throwable e ){
Debug.printStackTrace(e);
}
}
}
public void
addListener(
SSDPIGDListener l )
{
listeners.add( l );
}
public void
removeListener(
SSDPIGDListener l )
{
listeners.remove(l);
}
}