package org.openslx.satellitedaemon.filetransfer;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.List;
import org.apache.log4j.Logger;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;
import org.openslx.encryption.AsymEncryptionHandler;
import org.openslx.imagemaster.crcchecker.CrcFile;
import org.openslx.imagemaster.thrift.iface.AuthenticationException;
import org.openslx.imagemaster.thrift.iface.AuthorizationError;
import org.openslx.imagemaster.thrift.iface.AuthorizationException;
import org.openslx.imagemaster.thrift.iface.DownloadData;
import org.openslx.imagemaster.thrift.iface.ImageData;
import org.openslx.imagemaster.thrift.iface.ImageDataError;
import org.openslx.imagemaster.thrift.iface.ImageDataException;
import org.openslx.imagemaster.thrift.iface.ImageServer;
import org.openslx.imagemaster.thrift.iface.ServerSessionData;
import org.openslx.imagemaster.thrift.iface.UploadData;
import org.openslx.imagemaster.thrift.iface.UploadError;
import org.openslx.imagemaster.thrift.iface.UploadException;
import org.openslx.imagemaster.thrift.iface.UserInfo;
import org.openslx.satellitedaemon.Globals;
import org.openslx.satellitedaemon.Identity;
import org.openslx.satellitedaemon.db.DbImage;
import org.openslx.satellitedaemon.db.DbImage.Status;
/***********************************************************************************************/
/**
* Handles the authentication with the Satellite Server and sends the
* FILTRANSFERCredentials, which are necessary for the upload of the image.
*/
public class ThriftConnection
{
private static ThreadLocal<ImageServer.Client> client = new ThreadLocal<ImageServer.Client>();
private static ServerSessionData sSD = null;
private static Logger log = Logger.getLogger( ThriftConnection.class );
private static CrcFile crc = null;
/***********************************************************************************************/
/**
* Method for getting UploadeInfos
*
* when the CRCsum need to be transfered. The method calls getConnection()
* to check if the connection is ok and to get the ServerSessionData. If
* connection is ok, it calls submitImage with CRCsum in List<Integer>.
*
* @return returns 'null' if there is a problem.
*/
public static UploadData getUploadInfos( ImageData imDat, String path )
{
ImageServer.Client theClient = null;
String crcPath = path.concat( ".crc" );
theClient = getConnection();
if ( theClient == null ) {
log.error( "Client was null!" );
return null;
}
List<Integer> crcSums = null;
try {
crc = new CrcFile( crcPath );
log.info( "Made CRCFile from " + crcPath );
log.info( "crc.getCrcSums( ).size = " + crc.getCrcSums().size() );
crcSums = crc.getCrcSums();
} catch ( FileNotFoundException e ) {
log.debug( "crcFile " + crcPath + " not found." );
} catch ( IOException e ) {
log.error( "IOException", e );
}
try {
return theClient.submitImage( sSD.sessionId, imDat, crcSums );
} catch ( AuthorizationException e ) {
if ( e.number == AuthorizationError.NOT_AUTHENTICATED ) {
log.warn( "Suddenly nut authenticated anymore.", e );
} else if ( e.number == AuthorizationError.NO_PERMISSION ) {
log.error( "No permission for uploading.", e );
// TODO: add error message into database.
} else {
log.warn( "Unknown authorization error.", e );
}
} catch ( ImageDataException e ) {
if ( e.number == ImageDataError.INVALID_DATA ) {
log.warn( "Data for image not valid", e );
// TODO: add e.message into DB;
} else {
log.warn( "ImageDataException", e );
}
} catch ( UploadException e ) {
if ( e.number == UploadError.BROKEN_BLOCK ) {
// A Block was transmitted 20 times unsuccessfully.
// TODO: Mark the Image as corrupted.
} else if ( e.number == UploadError.INVALID_CRC ) {
// The CRC sum contained errors
if ( crc != null && !crc.isValid() )
crc.delete();
} else {
e.printStackTrace();
}
} catch ( TException e ) {
log.error( "TException", e );
}
return null;
}
/***********************************************************************************************/
/**
* Method for getting DonwloadInfos. Calls getConnection if client was null.
* You need to specify all Blocks you want to have in an List.
*
* @return returns 'null' if there is a problem.
*/
public static DownloadData getDownloadInfos( DbImage imDat )
{
ImageServer.Client theClient = null;
theClient = getConnection();
if ( theClient == null ) {
log.error( "Client was null!" );
return null;
}
try {
return theClient.getImage( sSD.sessionId, imDat.guid );
} catch ( ImageDataException e ) {
log.debug( "In catch - blog of thrift connection" );
if ( e.isSetNumber()
&& e.getNumber().equals( ImageDataError.INVALID_DATA ) ) {
// Data in the db is not valid
// TODO: add e.message into DB;
} else if ( e.getNumber().equals( ImageDataError.UNKNOWN_IMAGE ) ) {
// The image requested is not known.
// TODO: change field image_syncMode, so the image is not asked
// for again.
// For now just changed status of image. Currently no
// possibility for creating new useful state in DB. (Offenburg)
log.info( "Image not known. For skipping next time, mark as only_local." );
imDat.updateStatus( Status.only_local );
// Plus add a note in some way to mark as unknown by Server
} else {
e.printStackTrace();
}
} catch ( AuthorizationException e ) {
if ( e.isSetNumber()
&& e.getNumber().equals(
AuthorizationError.NOT_AUTHENTICATED ) ) {
log.error( "Not authenticated. SessionID is not valid.", e );
// SessionID is not valid
// TODO: Code for new SSID
} else if ( e.getNumber().equals( AuthorizationError.NO_PERMISSION ) ) {
log.error( "No permission error.", e );
// TODO: add e.message into database.
} else {
e.printStackTrace();
}
} catch ( TException e ) {
log.error( "TException", e );
}
return null;
}
/***********************************************************************************************/
/**
* This method checks if there is already a working connection. If not,
* newClient() establishes one. Also it does the Authentication if not done
* yet.
*
* @return returns the client if successful.
*/
private static ImageServer.Client getConnection()
{
ImageServer.Client theClient = client.get();
boolean isAuthenticated;
if ( theClient == null ) {
// There is no client instance for this thread, create a new one
log.info( "No existing client for this thread. Making a new client ..." );
theClient = newClient();
isAuthenticated = false;
if ( theClient == null ) {
log.debug( "The client was null after newClient()" );
return null;
}
} else {
// There is a client instance for this thread, see if it's still usable and authenticated
try {
isAuthenticated = theClient.isServerAuthenticated( sSD.sessionId );
log.debug( "Existing client is " + ( isAuthenticated ? "still" : "not" ) + " authenticated." );
} catch ( TException x ) {
theClient = newClient();
if ( theClient == null ) {
log.warn( "Masterserver connection fail" );
return null;
}
log.debug( "Existing client was not connected anymore." );
isAuthenticated = false;
}
}
if ( !isAuthenticated ) {
try {
ByteBuffer tmpBuffer = theClient
.startServerAuthentication( Identity
.getOrganizationName() );
byte[] toEncrypt = new byte[ tmpBuffer.remaining() ];
tmpBuffer.get( toEncrypt );
AsymEncryptionHandler aeh = new AsymEncryptionHandler(
Identity.getPrivateKey() );
byte[] byteArray = aeh.encryptMessage( toEncrypt );
sSD = theClient.serverAuthenticate(
Identity.getOrganizationName(),
ByteBuffer.wrap( byteArray ) );
} catch ( AuthenticationException e ) {
log.error( "ThriftConnection: AuthenticationException: Server Authetication was not sucessful.", e );
return null;
} catch ( TException e ) {
log.error( "ThriftConnection: TException: Server Authetication was not sucessful.", e );
return null;
}
log.info( "is Authenticated." );
}
return theClient;
}
/***********************************************************************************************/
/**
* Method for creating a new Client for Thrift communication.
*
* @throws IOException
*/
private static ImageServer.Client newClient()
{
final ImageServer.Client newClient;
try {
TTransport transport = new TFramedTransport( new TSocket(
Globals.getMasterserverHost(), Globals.getThriftPort() ) );
transport.open();
TProtocol protocol = new TBinaryProtocol( transport );
newClient = new ImageServer.Client( protocol );
log.debug( "ThriftConnection: Made a new Client" );
} catch ( TTransportException e ) {
log.error( "Transport could not be opened. Couldn't create new client.", e );
return null;
}
client.set( newClient );
return newClient;
}
public static boolean publishUser( UserInfo userInfo )
{
ImageServer.Client theClient = null;
theClient = getConnection();
if ( theClient == null ) {
log.error( "Client was null!" );
return false;
}
try {
return theClient.publishUser( sSD.sessionId, userInfo );
} catch ( AuthorizationException e ) {
log.error( "AutorizationException", e );
} catch ( TException e ) {
log.error( "TException", e );
}
return false;
}
}