MagnetURIHandlerImplpublic class MagnetURIHandlerImpl extends com.aelitis.net.magneturi.MagnetURIHandler
Fields Summary |
---|
private static final LogIDs | LOGID | private static MagnetURIHandlerImpl | singleton | private static AEMonitor | class_mon | private static final int | DOWNLOAD_TIMEOUT | protected static final String | NL | private static final boolean | DEBUG | private int | port | private List | listeners | private Map | info_map |
Constructors Summary |
---|
protected MagnetURIHandlerImpl()
ServerSocket socket = null;
for (int i=45100;i<=45199;i++){
try{
socket = new ServerSocket(i, 50, InetAddress.getByName("127.0.0.1"));
port = i;
break;
}catch( Throwable e ){
}
}
if ( socket == null ){
// no free sockets, not much we can do
if (Logger.isEnabled())
Logger.log(new LogEvent(LOGID, LogEvent.LT_ERROR,
"MagnetURI: no free sockets, giving up"));
}else{
if (Logger.isEnabled())
Logger.log(new LogEvent(LOGID, "MagnetURI: bound on "
+ socket.getLocalPort()));
final ServerSocket f_socket = socket;
Thread t =
new AEThread("MagnetURIHandler")
{
public void
runSupport()
{
int errors = 0;
int ok = 0;
while(true){
try{
final Socket sck = f_socket.accept();
ok++;
errors = 0;
Thread t =
new AEThread( "MagnetURIHandler:processor" )
{
public void
runSupport()
{
boolean close_socket = true;
try{
String address = sck.getInetAddress().getHostAddress();
if ( address.equals("localhost") || address.equals("127.0.0.1")) {
BufferedReader br = new BufferedReader(new InputStreamReader(sck.getInputStream(),Constants.DEFAULT_ENCODING));
String line = br.readLine();
if (DEBUG) {
System.out.println("=====");
System.out.println("Traffic Class: "
+ sck.getTrafficClass());
System.out.println("OS: " + sck.getOutputStream());
System.out.println("isBound? " + sck.isBound()
+ "; isClosed=" + sck.isClosed() + "; isConn="
+ sck.isConnected() + ";isIShutD "
+ sck.isInputShutdown() + ";isOShutD "
+ sck.isOutputShutdown());
System.out.println("- - - -");
System.out.println(line);
while (br.ready()) {
String extraline = br.readLine();
System.out.println(extraline);
}
System.out.println("=====");
}
if ( line != null ){
if ( line.toUpperCase().startsWith( "GET " )){
Logger.log(new LogEvent(LOGID,
"MagnetURIHandler: processing '" + line + "'"));
line = line.substring(4);
int pos = line.lastIndexOf(' ");
line = line.substring( 0, pos );
close_socket = process( line, sck.getOutputStream() );
}else{
Logger.log(new LogEvent(LOGID, LogEvent.LT_WARNING,
"MagnetURIHandler: invalid command - '" + line
+ "'"));
}
}else{
Logger.log(new LogEvent(LOGID, LogEvent.LT_WARNING,
"MagnetURIHandler: connect from "
+ "'" + address + "': no data read"));
}
}else{
Logger.log(new LogEvent(LOGID, LogEvent.LT_WARNING,
"MagnetURIHandler: connect from "
+ "invalid address '" + address + "'"));
}
}catch( Throwable e ){
if ( !(e instanceof IOException || e instanceof SocketException )){
Debug.printStackTrace(e);
}
}finally{
try{
// leave client to close socket if not requested
if ( close_socket ){
sck.close();
}
}catch( Throwable e ){
}
}
}
};
t.setDaemon( true );
t.start();
}catch( Throwable e ){
Debug.printStackTrace(e);
errors++;
if ( errors > 100 ){
if (Logger.isEnabled())
Logger.log(new LogEvent(LOGID,
"MagnetURIHandler: bailing out, too many socket errors"));
}
}
}
}
};
t.setDaemon( true );
t.start();
}
|
Methods Summary |
---|
public void | addInfo(java.lang.String name, int info)
info_map.put( name, new Integer(info));
Logger.log(new LogEvent(LOGID, LogEvent.LT_INFORMATION,"MagnetURIHandler: global info registered: " + name + " -> " + info ));
| public void | addListener(com.aelitis.net.magneturi.MagnetURIHandlerListener l)
listeners.add( l );
| protected java.lang.String | getJS(java.lang.String s)
return( "document.write(" + s + ");" + NL );
| protected java.lang.String | getJSS(java.lang.String s)
return( "document.write(\"" + s + "\");" + NL );
| protected java.lang.String | getMessageText(java.lang.String resource)
return( MessageText.getString( "MagnetURLHandler.report." + resource ));
| protected java.lang.String | getMessageText(java.lang.String resource, java.lang.String param)
return( MessageText.getString( "MagnetURLHandler.report." + resource, new String[]{ param } ));
| public int | getPort()
return( port );
| public static com.aelitis.net.magneturi.MagnetURIHandler | getSingleton()
try{
class_mon.enter();
if ( singleton == null ){
singleton = new MagnetURIHandlerImpl();
}
return( singleton );
}finally{
class_mon.exit();
}
| public static void | main(java.lang.String[] args)
new MagnetURIHandlerImpl();
try{
Thread.sleep(1000000);
}catch( Throwable e ){
}
| protected boolean | process(java.lang.String get, java.io.OutputStream os)
//System.out.println( "get = " + get );
// magnet:?xt=urn:sha1:YNCKHTQCWBTRNJIV4WNAE52SJUQCZO5C
Map params = new HashMap();
List source_params = new ArrayList();
int pos = get.indexOf( '?" );
if ( pos != -1 ){
StringTokenizer tok = new StringTokenizer( get.substring( pos+1 ), "&" );
if (DEBUG) {
System.out.println("params:" + get.substring( pos+1 ));
}
while( tok.hasMoreTokens()){
String arg = tok.nextToken();
pos = arg.indexOf( '=" );
if ( pos == -1 ){
params.put( arg.trim(), "" );
}else{
try{
String lhs = arg.substring( 0, pos ).trim();
String rhs = URLDecoder.decode( arg.substring( pos+1 ).trim(), Constants.DEFAULT_ENCODING);
params.put( lhs, rhs );
if ( lhs.equalsIgnoreCase( "xsource" )){
source_params.add( rhs );
}
}catch( UnsupportedEncodingException e ){
Debug.printStackTrace( e );
}
}
}
}
if ( get.startsWith( "/magnet10/badge.img" )){
for (int i=0;i<listeners.size();i++){
byte[] data = ((MagnetURIHandlerListener)listeners.get(i)).badge();
if ( data != null ){
writeReply( os, "image/gif", data );
return( true );
}
}
writeNotFound( os );
return( true );
}else if ( get.startsWith( "/magnet10/canHandle.img?" )){
String urn = (String)params.get( "xt" );
if ( urn != null && urn.startsWith( "urn:btih:")){
for (int i=0;i<listeners.size();i++){
byte[] data = ((MagnetURIHandlerListener)listeners.get(i)).badge();
if ( data != null ){
writeReply( os, "image/gif", data );
return( true );
}
}
}
writeNotFound( os );
return( true );
}else if ( get.startsWith( "/azversion" )){
writeReply( os, "text/plain", Constants.AZUREUS_VERSION );
return( true );
}else if ( get.startsWith( "/magnet10/options.js?" ) ||
get.startsWith( "/magnet10/default.js?" )){
String resp = "";
resp += getJS( "magnetOptionsPreamble" );
resp += getJSS( "<a href=\\\"http://127.0.0.1:\"+(45100+magnetCurrentSlot)+\"/select/?\"+magnetQueryString+\"\\\" target=\\\"_blank\\\">" );
resp += getJSS( "<img src=\\\"http://127.0.0.1:\"+(45100+magnetCurrentSlot)+\"/magnet10/badge.img\\\">" );
resp += getJSS( "Download with Azureus" );
resp += getJSS( "</a>" );
resp += getJS( "magnetOptionsPostamble" );
resp += "magnetOptionsPollSuccesses++";
writeReply( os, "application/x-javascript", resp );
return( true );
}else if ( get.startsWith( "/magnet10/pause" )){
try{
Thread.sleep( 250 );
}catch( Throwable e ){
}
writeNotFound( os );
return( true );
}else if ( get.startsWith( "/select/" )){
String fail_reason = "";
boolean ok = false;
String urn = (String)params.get( "xt" );
if ( urn == null ){
fail_reason = "xt missing";
}else{
try{
URL url;
if ( urn.startsWith( "http:") || urn.startsWith( "https:" )){
url = new URL( urn );
}else{
url = new URL( "magnet:?xt=" + urn );
}
for (int i=0;i<listeners.size();i++){
if (((MagnetURIHandlerListener)listeners.get(i)).download( url )){
ok = true;
break;
}
}
if ( !ok ){
fail_reason = "No listeners accepted the operation";
}
}catch( Throwable e ){
Debug.printStackTrace(e);
fail_reason = Debug.getNestedExceptionMessage(e);
}
}
if ( ok ){
if ( "image".equalsIgnoreCase((String)params.get( "result" ))){
for (int i=0;i<listeners.size();i++){
byte[] data = ((MagnetURIHandlerListener)listeners.get(i)).badge();
if ( data != null ){
writeReply( os, "image/gif", data );
return( true );
}
}
}
writeReply( os, "text/plain", "Download initiated" );
}else{
writeReply( os, "text/plain", "Download initiation failed: " + fail_reason );
}
}else if ( get.startsWith( "/download/" )){
String urn = (String)params.get( "xt" );
if ( urn == null || !( urn.startsWith( "urn:sha1:") || urn.startsWith( "urn:btih:"))){
if (Logger.isEnabled())
Logger.log(new LogEvent(LOGID, LogEvent.LT_WARNING,
"MagnetURIHandler: " + "invalid command - '" + get + "'"));
return( true );
}
final PrintWriter pw = new PrintWriter( new OutputStreamWriter( os, "UTF-8" ));
try{
pw.print( "HTTP/1.0 200 OK" + NL );
pw.flush();
String base_32 = urn.substring(9);
List sources = new ArrayList();
for (int i=0;i<source_params.size();i++){
String source = (String)source_params.get(i);
int p = source.indexOf(':");
if ( p != -1 ){
try{
InetSocketAddress sa = new InetSocketAddress( source.substring(0,p), Integer.parseInt( source.substring(p+1)));
sources.add( sa );
}catch( Throwable e ){
Debug.printStackTrace(e);
}
}
}
InetSocketAddress[] s = new InetSocketAddress[ sources.size()];
sources.toArray( s );
if (Logger.isEnabled())
Logger.log(new LogEvent(LOGID, "MagnetURIHandler: download of '"
+ base_32 + "' starts (initial sources=" + s.length + ")"));
byte[] sha1 = Base32.decode( base_32 );
byte[] data = null;
for (int i=0;i<listeners.size();i++){
data = ((MagnetURIHandlerListener)listeners.get(i)).download(
new MagnetURIHandlerProgressListener()
{
public void
reportSize(
long size )
{
pw.print( "X-Report: " + getMessageText( "torrent_size", String.valueOf( size )) + NL );
pw.flush();
}
public void
reportActivity(
String str )
{
pw.print( "X-Report: " + str + NL );
pw.flush();
}
public void
reportCompleteness(
int percent )
{
pw.print( "X-Report: " + getMessageText( "percent", String.valueOf(percent)) + NL );
pw.flush();
}
},
sha1,
s,
DOWNLOAD_TIMEOUT );
if ( data != null ){
break;
}
}
if (Logger.isEnabled())
Logger.log(new LogEvent(LOGID, "MagnetURIHandler: download of '"
+ base_32
+ "' completes, data "
+ (data == null ? "not found"
: ("found, length = " + data.length))));
if ( data != null ){
pw.print( "Content-Length: " + data.length + NL + NL );
pw.flush();
os.write( data );
os.flush();
}else{
// HACK: don't change the "error:" message below, it is used by TorrentDownloader to detect this
// condition
pw.print( "X-Report: error: " + getMessageText( "no_sources" ) + NL );
pw.flush();
// pause on error
return( !params.containsKey( "pause_on_error" ));
}
}catch( Throwable e ){
// don't remove the "error:" (see above)
pw.print( "X-Report: error: " + getMessageText( "error", Debug.getNestedExceptionMessage(e)) + NL );
pw.flush();
// Debug.printStackTrace(e);
// pause on error
return( !params.containsKey( "pause_on_error" ));
}
}else if ( get.startsWith( "/getinfo?" )){
String name = (String)params.get( "name" );
if ( name != null ){
Integer info = (Integer)info_map.get( name );
if ( info != null ){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int width = info.intValue();
int height = 1;
writeImage(baos, width, height);
byte[] data = baos.toByteArray();
writeReply( os, "image/bmp", data );
return( true );
}
}
writeNotFound( os );
return( true );
}else if ( get.startsWith( "/setinfo?" )){
String name = (String)params.get( "name" );
HashMap paramsCopy = new HashMap();
paramsCopy.putAll(params);
if ( name != null ){
boolean result = false;
for (int i=0;i<listeners.size() && !result;i++){
result = ((MagnetURIHandlerListener)listeners.get(i)).set( name, paramsCopy );
}
int width = result?20:10;
int height = result?20:10;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
writeImage(baos, width, height);
byte[] data = baos.toByteArray();
writeReply( os, "image/bmp", data );
return( true );
}
}
return( true );
| public void | removeListener(com.aelitis.net.magneturi.MagnetURIHandlerListener l)
listeners.remove( l );
| private void | write4Bytes(java.io.OutputStream os, long l)
try {
os.write((int) (l & 0xFF));
os.write((int) ((l >> 8) & 0xFF));
os.write((int) ((l >> 16) & 0xFF));
os.write((int) ((l >> 24) & 0xFF));
} catch (IOException e) {
Debug.out(e);
}
| private void | writeImage(java.io.OutputStream os, int width, int height)
int rowWidth = width / 8;
if ((rowWidth % 4) != 0) {
rowWidth = ((rowWidth / 4) + 1) * 4;
}
int imageSize = rowWidth * height;
int fileSize = 54 + imageSize;
try {
os.write(new byte[] {
'B",
'M"
});
write4Bytes(os, fileSize);
write4Bytes(os, 0);
write4Bytes(os, 54); // data pos
write4Bytes(os, 40); // header size
write4Bytes(os, width);
write4Bytes(os, height);
write4Bytes(os, (1 << 16) + 1); // 1 plane and 1 bpp color
write4Bytes(os, 0);
write4Bytes(os, imageSize);
write4Bytes(os, 0);
write4Bytes(os, 0);
write4Bytes(os, 0);
write4Bytes(os, 0);
byte[] data = new byte[imageSize];
os.write(data);
} catch (IOException e) {
Debug.out(e);
}
| protected void | writeNotFound(java.io.OutputStream os)
PrintWriter pw = new PrintWriter( new OutputStreamWriter( os ));
pw.print( "HTTP/1.0 404 Not Found" + NL + NL );
pw.flush();
| protected void | writeReply(java.io.OutputStream os, java.lang.String content_type, java.lang.String content)
writeReply( os, content_type, content.getBytes());
| protected void | writeReply(java.io.OutputStream os, java.lang.String content_type, byte[] content)
PrintWriter pw = new PrintWriter( new OutputStreamWriter( os ));
pw.print( "HTTP/1.1 200 OK" + NL );
pw.print( "Cache-Control: no-cache" + NL );
pw.print( "Pragma: no-cache" + NL );
pw.print( "Content-Type: " + content_type + NL );
pw.print( "Content-Length: " + content.length + NL + NL );
pw.flush();
os.write( content );
|
|