/**
* Copyright (C) 2009-2014 Cars and Tracks Development Project (CTDP).
*
* 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.
*/
package net.ctdp.rfdynhud.plugins.datasender;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.Arrays;
import org.jagatoo.util.strings.MD5Util;
/**
* Connects via a socket using TCP and sends/receives data (server side).
*
* @author Marvin Froehlich (CTDP)
*/
public abstract class AbstractServerCommunicator extends AbstractCommunicator
{
private final byte[] passwordHash;
private boolean connected = false;
/**
* Gets the server's name for use in connection requests.
*
* @return a 32 bytes array.
*/
protected abstract byte[] getServerName();
protected abstract boolean isRunning();
@Override
public final boolean isConnected()
{
return ( connected );
}
protected abstract boolean isInCockpit();
protected abstract void onConnectionEsteblished();
/**
*
* @param code
* @param in
*
* @return <code>true</code>, if the datagram was recognized, <code>false</code> otherwise.
*
* @throws IOException
*/
protected abstract boolean readDatagram( final short code, DataInputStream in ) throws IOException;
protected final void readInput( DataInputStream in ) throws IOException
{
short code = in.readShort();
//plugin.debug( "Received command code: ", code - CommunicatorConstants.OFFSET );
switch ( code )
{
case CONNECTION_REQUEST:
byte[] serverName = getServerName();
if ( serverName == null )
throw new Error( "Wrong implementation: getServerName() returned a null value." );
if ( serverName.length != 32 )
throw new Error( "Wrong implementation: getServerName() returned an array of length " + serverName.length + ". Must be 32." );
startCommandImpl( SERVER_NAME );
writeImpl( serverName );
endCommandImpl();
break;
case CONNECTION_REQUEST2:
if ( passwordHash == null )
{
startCommandImpl( CONNECTION_ESTEBLISHED );
eventsBuffer.writeBoolean( isInCockpit() );
endCommandImpl();
connected = true;
onConnectionEsteblished();
}
else
{
writeSimpleCommandImpl( REQUEST_PASSWORD );
}
break;
case PASSWORD_HASH:
byte[] bytes = new byte[ 16 ];
in.read( bytes );
if ( Arrays.equals( bytes, passwordHash ) )
{
startCommandImpl( CONNECTION_ESTEBLISHED );
eventsBuffer.writeBoolean( isInCockpit() );
endCommandImpl();
connected = true;
onConnectionEsteblished();
}
else
{
writeSimpleCommandImpl( PASSWORD_MISMATCH );
}
break;
case CONNECTION_CLOSED:
close( true );
break;
default:
if ( !readDatagram( code, in ) )
log( "WARNING: Unknown command code read: " + code );
}
}
public abstract void connect();
protected abstract void close( boolean restart );
public final void close()
{
close( false );
}
protected abstract void onConnectionClosed();
public AbstractServerCommunicator( String password )
{
this.passwordHash = ( ( password == null ) || password.equals( "" ) ) ? null : MD5Util.md5Bytes( password );
}
}