/*
** j###t ########## #### ####
** j###t ########## #### ####
** j###T "###L J###"
** ######P' ########## #########
** ######k, ########## T######T
** ####~###L ####
** #### q###L ########## .#####
** #### \###L ########## #####"
*/
package key;
import java.net.Socket;
import java.net.InetAddress;
import java.io.*;
import java.util.Hashtable;
/**
*/
public abstract class SocketIC
extends InteractiveConnection
{
public static final AtomicElement[] ELEMENTS =
{
// String getName();
AtomicElement.construct( SocketIC.class, Integer.TYPE, "localPort",
AtomicElement.PUBLIC_ACCESSORS | AtomicElement.READ_ONLY,
"the local port number of this connection" ),
AtomicElement.construct( SocketIC.class, Integer.TYPE, "remotePort",
AtomicElement.PUBLIC_ACCESSORS | AtomicElement.READ_ONLY,
"the remote port number of this connection" ),
AtomicElement.construct( SocketIC.class, String.class, "address",
AtomicElement.PUBLIC_ACCESSORS | AtomicElement.READ_ONLY,
"the address that this connection is to" ),
AtomicElement.construct( SocketIC.class, Site.class, "site",
AtomicElement.PUBLIC_FIELD,
"the site that this connection is to" )
};
public static final AtomicStructure STRUCTURE = new AtomicStructure( InteractiveConnection.STRUCTURE, ELEMENTS );
public static final int MAXIMUM_CONNECTIONS_OPEN = 200;
private static int connectionCount = 0;
Socket socket;
Writer output;
PushbackInputStream inputStream;
public transient Site site;
public int getLocalPort() { return( socket.getLocalPort() ); }
public int getRemotePort() { return( socket.getPort() ); }
public String getAddress() { return( socket.getInetAddress().toString() ); }
String identString = "";
/**
* The constructor must take a socket as its sole
* argument
*
* @param s The socket that the connection is on
*/
public SocketIC( Socket s ) throws IOException
{
socket = s;
connectionCount++;
try
{
output = new BufferedWriter( new OutputStreamWriter( socket.getOutputStream() ) );
inputStream = new PushbackInputStream( socket.getInputStream() );
}
catch( IOException e )
{
close();
throw e;
}
if( connectionCount > MAXIMUM_CONNECTIONS_OPEN )
{
close();
throw new LimitExceededException( "too many open connections" );
}
InetAddress inetAddress = s.getInetAddress();
//Log.debug( this, "Connected to: " + inetAddress.getHostName() +":"+ socket.getPort() );
Internet inet = Key.getInternet();
byte[] baddress = inetAddress.getAddress();
int[] address = new int[ baddress.length ];
for( int i = 0; i < baddress.length; i++ )
{
if( baddress[i] < 0 )
address[i] = 256 + baddress[i];
else
address[i] = baddress[i];
}
site = inet.search( address );
if( site == null )
{
//Log.debug( this, "search for " + inetAddress.toString() + " failed." );
site = new Site( address );
inet.insert( site );
}
//else
//Log.debug( this, "search (inet) suceeded: " + site.toString() );
String dns = inetAddress.getHostName();
if( dns != null && !Character.isDigit( dns.charAt( 0 ) ) )
site.registerSite( dns );
site.connectionStats().startConnection();
if( key.Main.SOCKET_IDENT_LOOKUP )
{
new key.util.Ident( socket, new key.util.Ident.Callback()
{
public void identResolvedError( String error )
{
identString = "<" + error + "> ";
}
public void identProtocolError( String error )
{
identString = "<" + error + "> ";
}
public void identResolvedUserId( String machine, String user )
{
identString = "<" + machine + "> " + user + "@";
}
} ).start();
}
}
public String getName()
{
return( super.getName() + " " + getFullSiteName() );
}
public AtomicStructure getDeclaredStructure()
{
return( STRUCTURE );
}
public final String getSiteName()
{
return( socket.getInetAddress().getHostName() );
}
public final boolean newbiesAllowed()
{
return( site.newbiesAllowed() );
}
public void flush()
{
try
{
output.flush();
}
catch( IOException e )
{
throw new NetworkException( e );
}
}
public final String getFullSiteName()
{
InetAddress ia = socket.getInetAddress();
return( identString + ia.getHostName() + " [" + ia.getHostAddress() + "]" );
}
public final String getSiteIP()
{
InetAddress ia = socket.getInetAddress();
return( ia.getHostAddress() );
}
public final Site getSite()
{
return( site );
}
public final void discard() throws IOException
{
inputStream.skip( inputStream.available() );
}
public final void printStackTrace( Throwable t )
{
PrintWriter pw = new PrintWriter( output );
t.printStackTrace( pw );
pw.flush();
}
public void finalize() throws Throwable
{
super.finalize();
if( socket != null )
{
try
{
socket.close();
}
catch( IOException e )
{
}
finally
{
socket = null;
connectionCount--;
}
}
}
public synchronized void close()
{
super.close();
if( site != null )
{
site.connectionStats().endConnection();
site = null;
}
if( socket != null )
{
try
{
socket.close();
}
catch( Exception t )
{
}
finally
{
if( socket != null )
{
socket = null;
connectionCount--;
}
Registry.instance.delete( this );
}
}
}
/**
* return true if the socket is still open
*/
public boolean isConnected()
{
if( socket != null )
return true;
else
return false;
}
/**
* This function will be called every 'now and
* again', as a 'check' function when no input
* is required (we're not waiting), but some
* is allowed. This is useful for the telnet
* protocol in particular, which can recieve
* IAC's before the login prompt. This function
* should be harmless, no matter when its called
*/
public abstract void check() throws IOException;
}