From 036807ab4006bf81188e5324fa53e34b1c7d5ae6 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Fri, 25 Jul 2014 14:20:00 +0200 Subject: [Filetransfer] Add more sanity checks and error handling, remodel class structure, introduce common base class for Uploader and Downloader --- .../java/org/openslx/filetransfer/ClassTest.java | 4 +- .../java/org/openslx/filetransfer/Downloader.java | 322 ++------------------ .../java/org/openslx/filetransfer/Listener.java | 20 +- .../java/org/openslx/filetransfer/Transfer.java | 327 +++++++++++++++++++++ .../java/org/openslx/filetransfer/Uploader.java | 327 +++------------------ 5 files changed, 405 insertions(+), 595 deletions(-) create mode 100644 src/main/java/org/openslx/filetransfer/Transfer.java (limited to 'src/main/java/org/openslx/filetransfer') diff --git a/src/main/java/org/openslx/filetransfer/ClassTest.java b/src/main/java/org/openslx/filetransfer/ClassTest.java index 998e3c7..4550060 100644 --- a/src/main/java/org/openslx/filetransfer/ClassTest.java +++ b/src/main/java/org/openslx/filetransfer/ClassTest.java @@ -79,7 +79,7 @@ public class ClassTest d.setOutputFilename( "output.txt" ); d.sendToken( "xyz" ); while ( d.readMetaData() ) - d.readBinary(); + d.receiveBinary(); /* String pathToKeyStore = @@ -145,6 +145,6 @@ class Test implements IncomingEvent { downloader.setOutputFilename( "output.txt" ); while ( downloader.readMetaData() ) - downloader.readBinary(); + downloader.receiveBinary(); } } diff --git a/src/main/java/org/openslx/filetransfer/Downloader.java b/src/main/java/org/openslx/filetransfer/Downloader.java index c860f5e..da882b9 100644 --- a/src/main/java/org/openslx/filetransfer/Downloader.java +++ b/src/main/java/org/openslx/filetransfer/Downloader.java @@ -1,74 +1,46 @@ package org.openslx.filetransfer; -import java.io.DataInputStream; -import java.io.DataOutputStream; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.net.SocketTimeoutException; -import java.nio.charset.StandardCharsets; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocket; -import javax.net.ssl.SSLSocketFactory; import org.apache.log4j.Logger; -public class Downloader +public class Downloader extends Transfer { // Some instance variables. - private SSLSocketFactory sslSocketFactory; - private SSLSocket satelliteSocket; - private DataOutputStream dataToServer; - private DataInputStream dataFromServer; - private String TOKEN = null; - private String RANGE = null; private String outputFilename = null; - private String ERROR = null; - private static Logger log = Logger.getLogger( Downloader.class ); + private static final Logger log = Logger.getLogger( Downloader.class ); /***********************************************************************/ /** - * Constructor for satellite downloader. - * Tries to connect to specific ip and port and sending type of action. + * Actively initiate a connection to a remote peer for downloading. * - * @param ip - * @param port + * @param host Host name or address to connect to + * @param port Port to connect to + * @throws IOException */ - public Downloader( String ip, int port, SSLContext context ) + public Downloader( String host, int port, SSLContext context ) throws IOException { - try { - // create socket. - sslSocketFactory = context.getSocketFactory(); - - satelliteSocket = (SSLSocket)sslSocketFactory.createSocket( ip, port ); - satelliteSocket.setSoTimeout( 2000 ); // set socket timeout. - - dataToServer = new DataOutputStream( satelliteSocket.getOutputStream() ); - dataToServer.writeByte( 'D' ); - dataFromServer = new DataInputStream( satelliteSocket.getInputStream() ); - } catch ( Exception e ) { - e.printStackTrace(); - } + super( host, port, context, log ); + dataToServer.writeByte( 'D' ); } /***********************************************************************/ /** - * Constructor for master downloader. - * Given parameter is the socket over which the transfer is going. + * Constructor used by Listener to create an incoming download connection. * - * @param socket + * @param socket established connection to peer which requested an upload. + * @throws IOException */ - public Downloader( SSLSocket socket ) + protected Downloader( SSLSocket socket ) throws IOException { - try { - satelliteSocket = socket; - dataToServer = new DataOutputStream( satelliteSocket.getOutputStream() ); - dataFromServer = new DataInputStream( satelliteSocket.getInputStream() ); - } catch ( IOException e ) { - e.printStackTrace(); - } + super( socket, log ); } /***********************************************************************/ @@ -95,211 +67,16 @@ public class Downloader /***********************************************************************/ /** - * Method for sending token for identification from satellite to master. - * - * @param t - */ - public Boolean sendToken( String token ) - { - try { - TOKEN = token; - String sendToken = "TOKEN=" + TOKEN; - byte[] data = sendToken.getBytes( StandardCharsets.UTF_8 ); - dataToServer.writeByte( data.length ); - dataToServer.write( data ); - } catch ( SocketTimeoutException ste ) { - ste.printStackTrace(); - log.info( "Socket timeout occured ... close connection." ); - this.close(); - } catch ( IOException e ) { - e.printStackTrace(); - readMetaData(); - if ( ERROR != null ) { - if ( ERROR == "timeout" ) { - log.info( "Socket timeout occured ... close connection." ); - this.close(); - } - } - log.info( "Sending TOKEN in Downloader failed..." ); - return false; - } - return true; - } - - /***********************************************************************/ - /** - * Method to send range of the file, which should be uploaded. - * Helpful for knowing how much was already uploaded if - * connection aborts. - * - * @param a - * @param b - */ - public Boolean sendRange( int a, int b ) - { - try { - RANGE = a + ":" + b; - String sendRange = "RANGE=" + RANGE; - byte[] data = sendRange.getBytes( StandardCharsets.UTF_8 ); - dataToServer.writeByte( data.length ); - dataToServer.write( data ); - } catch ( SocketTimeoutException ste ) { - ste.printStackTrace(); - log.info( "Socket timeout occured ... close connection." ); - this.close(); - } catch ( IOException e ) { - e.printStackTrace(); - readMetaData(); - if ( ERROR != null ) { - if ( ERROR == "timeout" ) { - log.info( "Socket timeout occured ... close connection." ); - this.close(); - } - } - log.info( "Sending RANGE in Uploader failed..." ); - return false; - } - return true; - } - - /***********************************************************************/ - /** - * Method for reading incoming token for identification. + * Method to request a byte range within the file to download. This + * method is called by the party that initiated the connection. * + * @param startOffset offset in file where to start the transfer (inclusive) + * @param endOffset end offset where to end the transfer (exclusive) + * @return success or failure */ - public String getToken() + public boolean requestRange( int startOffset, int endOffset ) { - return TOKEN; - } - - /***********************************************************************/ - /** - * Method for reading range of file, which is downloaded. - * Helpful for knowing how much is already downloaded if connection aborts. - */ - public String getRange() - { - return RANGE; - } - - /***********************************************************************/ - /** - * Getter for beginning of RANGE. - * - * @return - */ - public int getStartOfRange() - { - if ( RANGE != null ) { - String[] splitted = RANGE.split( ":" ); - return Integer.parseInt( splitted[0] ); - } - return -1; - } - - /***********************************************************************/ - /** - * Getter for end of RANGE. - * - * @return - */ - public int getEndOfRange() - { - if ( RANGE != null ) { - String[] splitted = RANGE.split( ":" ); - return Integer.parseInt( splitted[1] ); - } - return -1; - } - - /***********************************************************************/ - /** - * Method for returning difference of current Range. - * - * @return - */ - public int getDiffOfRange() - { - int diff = Math.abs( getEndOfRange() - getStartOfRange() ); - return diff; - } - - /***********************************************************************/ - /** - * Method for reading MetaData, like TOKEN and FileRange. - * Split incoming bytes after first '=' and store value to specific - * variable. - * - */ - public Boolean readMetaData() - { - try { - while ( true ) { - byte[] incoming = new byte[ 255 ]; // TODO: problematische Größe. - - // First get length. - int retLengthByte; - retLengthByte = dataFromServer.read( incoming, 0, 1 ); - if (retLengthByte != 1) { - this.close(); - return false; - } - - int length = incoming[0] & 0xFF; - log.info( "length (downloader): " + length ); - - if ( length == 0 ) - break; - - /** - * Read the next available bytes and split by '=' for - * getting TOKEN or RANGE. - */ - int hasRead = 0; - while ( hasRead < length ) { - int ret = dataFromServer.read( incoming, hasRead, length - hasRead ); - if ( ret == -1 ) { - log.info( "Error occured while reading Metadata." ); - return false; - } - hasRead += ret; - } - - String data = new String( incoming, 0, length, "UTF-8" ); - // System.out.println(data); - - String[] splitted = data.split( "=" ); - // System.out.println("splitted[0]: " + splitted[0]); - // System.out.println("splitted[1]: " + splitted[1]); - if ( splitted[0] != null && splitted[0].equals( "TOKEN" ) ) { - if ( splitted[1] != null ) - TOKEN = splitted[1]; - log.info( "TOKEN: " + TOKEN ); - } - else if ( splitted[0].equals( "RANGE" ) ) { - if ( splitted[1] != null ) - RANGE = splitted[1]; - log.info( "RANGE: '" + RANGE + "'" ); - } - else if ( splitted[0].equals( "ERROR" ) ) { - if ( splitted[1] != null ) - ERROR = splitted[1]; - log.info( "ERROR: " + ERROR ); - return false; - } - } - } catch ( SocketTimeoutException ste ) { - ste.printStackTrace(); - sendErrorCode( "timeout" ); - log.info( "Socket Timeout occured in Downloader." ); - this.close(); - return false; - } catch ( Exception e ) { - e.printStackTrace(); - this.close(); - return false; - } - return true; + return super.sendRange( startOffset, endOffset ); } /***********************************************************************/ @@ -307,21 +84,20 @@ public class Downloader * Method for reading Binary. Reading the current Range of incoming binary. * */ - public Boolean readBinary() + public boolean receiveBinary() { RandomAccessFile file = null; try { - int length = getDiffOfRange(); - byte[] incoming = new byte[ 4000 ]; + int chunkLength = getDiffOfRange(); + byte[] incoming = new byte[ 64000 ]; int hasRead = 0; file = new RandomAccessFile( new File( outputFilename ), "rw" ); file.seek( getStartOfRange() ); - while ( hasRead < length ) { - int ret = dataFromServer.read( incoming, 0, Math.min( length - hasRead, incoming.length ) ); + while ( hasRead < chunkLength ) { + int ret = dataFromServer.read( incoming, 0, Math.min( chunkLength - hasRead, incoming.length ) ); // log.info("hasRead: " + hasRead + " length: " + length + " ret: " + ret); if ( ret == -1 ) { - log.info( "Error occured in Downloader.readBinary()," - + " while reading binary." ); + log.info( "Error occured while receiving payload." ); return false; } hasRead += ret; @@ -333,6 +109,7 @@ public class Downloader sendErrorCode( "timeout" ); log.info( "Socket timeout occured ... close connection." ); this.close(); + return false; } catch ( Exception e ) { e.printStackTrace(); log.info( "Reading RANGE " + getStartOfRange() + ":" + getEndOfRange() @@ -347,49 +124,8 @@ public class Downloader e.printStackTrace(); } } + RANGE = null; // Reset range for next iteration } return true; } - - /***********************************************************************/ - /** - * Method for sending error Code to server. For example in case of wrong - * token, send code for wrong token. - * - */ - public Boolean sendErrorCode( String errString ) - { - try { - String sendError = "ERROR=" + errString; - byte[] data = sendError.getBytes( StandardCharsets.UTF_8 ); - dataToServer.writeByte( data.length ); - dataToServer.write( data ); - } catch ( IOException e ) { - e.printStackTrace(); - this.close(); - return false; - } - return true; - } - - /***********************************************************************/ - /** - * Method for closing connection, if download has finished. - * - */ - public void close() - { - try { - if ( satelliteSocket != null ) { - this.satelliteSocket.close(); - satelliteSocket = null; - } - if ( dataFromServer != null ) - dataFromServer.close(); - if ( dataToServer != null ) - dataToServer.close(); - } catch ( IOException e ) { - e.printStackTrace(); - } - } } diff --git a/src/main/java/org/openslx/filetransfer/Listener.java b/src/main/java/org/openslx/filetransfer/Listener.java index 778804d..04f82f5 100644 --- a/src/main/java/org/openslx/filetransfer/Listener.java +++ b/src/main/java/org/openslx/filetransfer/Listener.java @@ -1,5 +1,7 @@ package org.openslx.filetransfer; +import java.io.IOException; + import javax.net.ssl.SSLContext; import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLServerSocketFactory; @@ -42,10 +44,10 @@ public class Listener extends Thread */ private void listen() { + SSLServerSocket welcomeSocket = null; try { SSLServerSocketFactory sslServerSocketFactory = context.getServerSocketFactory(); - SSLServerSocket welcomeSocket = - (SSLServerSocket)sslServerSocketFactory.createServerSocket( this.port ); + welcomeSocket = (SSLServerSocket)sslServerSocketFactory.createServerSocket( this.port ); while ( !isInterrupted() ) { SSLSocket connectionSocket = (SSLSocket)welcomeSocket.accept(); @@ -54,27 +56,33 @@ public class Listener extends Thread byte[] b = new byte[ 1 ]; int length = connectionSocket.getInputStream().read( b ); - log.info( "Length (Listener): " + length ); + log.debug( "Length (Listener): " + length ); if ( b[0] == U ) { - log.info( "recognized U --> starting Downloader" ); + log.debug( "recognized U --> starting Downloader" ); // --> start Downloader(socket). Downloader d = new Downloader( connectionSocket ); incomingEvent.incomingDownloader( d ); } else if ( b[0] == D ) { - log.info( "recognized D --> starting Uploader" ); + log.debug( "recognized D --> starting Uploader" ); // --> start Uploader(socket). Uploader u = new Uploader( connectionSocket ); incomingEvent.incomingUploader( u ); } else { - log.info( "Got invalid option ... close connection" ); + log.debug( "Got invalid option ... close connection" ); connectionSocket.close(); } } } catch ( Exception e ) { e.printStackTrace(); // same as writing to System.err.println(e.toString). + } finally { + try { + welcomeSocket.close(); + } catch (IOException e) { + // Nothing we can do + } } } diff --git a/src/main/java/org/openslx/filetransfer/Transfer.java b/src/main/java/org/openslx/filetransfer/Transfer.java new file mode 100644 index 0000000..34868e3 --- /dev/null +++ b/src/main/java/org/openslx/filetransfer/Transfer.java @@ -0,0 +1,327 @@ +package org.openslx.filetransfer; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.SocketTimeoutException; +import java.nio.charset.StandardCharsets; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; + +import org.apache.log4j.Logger; + +public abstract class Transfer +{ + protected final SSLSocketFactory sslSocketFactory; + protected final SSLSocket satelliteSocket; + protected final DataOutputStream dataToServer; + protected final DataInputStream dataFromServer; + protected String TOKEN = null; + protected int[] RANGE = null; + protected String ERROR = null; + + protected final Logger log; + + protected Transfer( String ip, int port, SSLContext context, Logger log ) throws IOException + { + this.log = log; + // create socket. + sslSocketFactory = context.getSocketFactory(); + + satelliteSocket = (SSLSocket)sslSocketFactory.createSocket( ip, port ); + satelliteSocket.setSoTimeout( 2000 ); // set socket timeout. + + dataToServer = new DataOutputStream( satelliteSocket.getOutputStream() ); + dataFromServer = new DataInputStream( satelliteSocket.getInputStream() ); + } + + protected Transfer( SSLSocket socket, Logger log ) throws IOException + { + this.log = log; + satelliteSocket = socket; + dataToServer = new DataOutputStream( satelliteSocket.getOutputStream() ); + dataFromServer = new DataInputStream( satelliteSocket.getInputStream() ); + sslSocketFactory = null; + } + + protected boolean sendRange( int startOffset, int endOffset ) + { + if ( RANGE != null ) { + log.warn( "Range already set!" ); + return false; + } + try { + sendKeyValuePair( "RANGE", startOffset + ":" + endOffset ); + } catch ( SocketTimeoutException ste ) { + ste.printStackTrace(); + log.info( "Socket timeout occured ... close connection." ); + this.close(); + } catch ( IOException e ) { + e.printStackTrace(); + readMetaData(); + if ( ERROR != null ) { + if ( ERROR == "timeout" ) { + log.info( "Socket timeout occured ... close connection." ); + this.close(); + } + } + log.info( "Sending RANGE in Uploader failed..." ); + return false; + } + return true; + } + + /***********************************************************************/ + /** + * Method for sending token for identification from satellite to master. + * + * @param token The token to send + */ + public boolean sendToken( String token ) + { + if ( TOKEN != null ) { + log.warn( "Trying to send token while a token is already set! Ignoring..." ); + return false; + } + TOKEN = token; + try { + sendKeyValuePair( "TOKEN", TOKEN ); + } catch ( SocketTimeoutException ste ) { + ste.printStackTrace(); + log.info( "Socket timeout occured ... close connection." ); + this.close(); + } catch ( IOException e ) { + e.printStackTrace(); + readMetaData(); + if ( ERROR != null ) { + if ( ERROR == "timeout" ) { + log.info( "Socket timeout occured ... close connection." ); + this.close(); + } + } + log.info( "Sending TOKEN in Downloader failed..." ); + return false; + } + return true; + } + + /***********************************************************************/ + /** + * Method for reading incoming token for identification. + * + */ + public String getToken() + { + return TOKEN; + } + + private boolean parseRange( String range ) + { + if ( range == null ) + return true; + if ( RANGE != null ) { + log.warn( "Warning: RANGE already set when trying to parse from " + range ); + return false; + } + String parts[] = range.split( ":", 2 ); + int ret[] = new int[ 2 ]; + try { + ret[0] = Integer.parseInt( parts[0] ); + ret[1] = Integer.parseInt( parts[1] ); + } catch ( Throwable t ) { + log.warn( "Not parsable range: '" + range + "'" ); + return false; + } + if ( ret[1] <= ret[0] ) { + log.warn( "Invalid range. Start >= end" ); + return false; + } + RANGE = ret; + return true; + } + + /***********************************************************************/ + /** + * Getter for beginning of RANGE. + * + * @return + */ + public int getStartOfRange() + { + if ( RANGE != null ) { + return RANGE[0]; + } + return -1; + } + + /***********************************************************************/ + /** + * Getter for end of RANGE. + * + * @return + */ + public int getEndOfRange() + { + if ( RANGE != null ) { + return RANGE[1]; + } + return -1; + } + + /***********************************************************************/ + /** + * Method for returning difference of current Range. + * + * @return + */ + public int getDiffOfRange() + { + int diff = Math.abs( getEndOfRange() - getStartOfRange() ); + return diff; + } + + /***********************************************************************/ + /** + * Method for reading MetaData, like TOKEN and FileRange. + * Split incoming bytes after first '=' and store value to specific + * variable. + * + * @return true on success, false if reading failed + */ + public boolean readMetaData() + { + try { + while ( true ) { + byte[] incoming = new byte[ 255 ]; + + // First get length. + int retLengthByte; + retLengthByte = dataFromServer.read( incoming, 0, 1 ); + if ( retLengthByte != 1 ) { + this.close(); + return false; + } + + int length = incoming[0] & 0xFF; + log.debug( "length (downloader): " + length ); + + if ( length == 0 ) + break; + + /* + * Read the next available bytes and split by '=' for + * getting TOKEN or RANGE. + */ + int hasRead = 0; + while ( hasRead < length ) { + int ret = dataFromServer.read( incoming, hasRead, length - hasRead ); + if ( ret == -1 ) { + log.warn( "Error occured while reading Metadata." ); + this.close(); + return false; + } + hasRead += ret; + } + + String data = new String( incoming, 0, length, StandardCharsets.UTF_8 ); + + String[] splitted = data.split( "=", 2 ); + if ( splitted.length != 2 ) { + log.warn( "Invalid key value pair received (" + data + ")" ); + continue; + } + if ( splitted[0].equals( "TOKEN" ) ) { + if ( TOKEN != null ) { + log.warn( "Received a token when a token is already set!" ); + this.close(); + return false; + } + TOKEN = splitted[1]; + log.debug( "TOKEN: " + TOKEN ); + } + else if ( splitted[0].equals( "RANGE" ) ) { + if ( !parseRange( splitted[1] ) ) { + this.close(); + return false; + } + log.debug( "RANGE: '" + splitted[1] + "'" ); + } + else if ( splitted[0].equals( "ERROR" ) ) { + ERROR = splitted[1]; + log.debug( "ERROR: " + ERROR ); + } + } + } catch ( SocketTimeoutException ste ) { + ste.printStackTrace(); + sendErrorCode( "timeout" ); + log.info( "Socket Timeout occured in Downloader." ); + this.close(); + return false; + } catch ( Exception e ) { + e.printStackTrace(); + this.close(); + return false; + } + return true; + } + + private void sendKeyValuePair( String key, String value ) throws IOException + { + byte[] data = ( key + "=" + value ).getBytes( StandardCharsets.UTF_8 ); + dataToServer.writeByte( data.length ); + dataToServer.write( data ); + } + + /***********************************************************************/ + /** + * Method for sending error Code to server. For example in case of wrong + * token, send code for wrong token. + * + */ + public Boolean sendErrorCode( String errString ) + { + try { + sendKeyValuePair( "ERROR", errString ); + } catch ( IOException e ) { + e.printStackTrace(); + this.close(); + return false; + } + return true; + } + + /***********************************************************************/ + /** + * Method for closing connection, if download has finished. + * + */ + public void close() + { + try { + if ( satelliteSocket != null ) { + this.satelliteSocket.close(); + } + if ( dataFromServer != null ) + dataFromServer.close(); + if ( dataToServer != null ) + dataToServer.close(); + } catch ( IOException e ) { + e.printStackTrace(); + } + } + + /** + * Returns whether this transfer/connection is considered valid or usable, + * which means the socket is still properly connected to the remote peer. + * + * @return true or false + */ + public boolean isValid() + { + return satelliteSocket.isConnected() && !satelliteSocket.isClosed() + && !satelliteSocket.isInputShutdown() && !satelliteSocket.isOutputShutdown(); + } + +} diff --git a/src/main/java/org/openslx/filetransfer/Uploader.java b/src/main/java/org/openslx/filetransfer/Uploader.java index 60b9dd6..ff74a9a 100644 --- a/src/main/java/org/openslx/filetransfer/Uploader.java +++ b/src/main/java/org/openslx/filetransfer/Uploader.java @@ -1,65 +1,33 @@ package org.openslx.filetransfer; -import java.io.DataInputStream; -import java.io.DataOutputStream; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.net.SocketTimeoutException; -import java.net.UnknownHostException; -import java.nio.charset.StandardCharsets; -import java.security.KeyManagementException; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateException; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocket; -import javax.net.ssl.SSLSocketFactory; import org.apache.log4j.Logger; -public class Uploader +public class Uploader extends Transfer { - // Some member variables. - private SSLSocketFactory sslSocketFactory; - private SSLSocket satelliteSocket; - private DataOutputStream dataToServer; - private DataInputStream dataFromServer; - private String TOKEN = null; - private String RANGE = null; - private String ERROR = null; - private static Logger log = Logger.getLogger( Uploader.class ); + private static final Logger log = Logger.getLogger( Uploader.class ); /***********************************************************************/ /** - * Constructor for satellite uploader. - * Tries to connect to specific ip and port and sending type of action. + * Actively establish upload connection to given peer. * - * @param ip - * @param port + * @param host Host name or address to connect to + * @param port Port to connect to + * @param context ssl context for establishing a secure connection * @throws IOException - * @throws KeyStoreException - * @throws CertificateException - * @throws NoSuchAlgorithmException - * @throws KeyManagementException - * @throws UnknownHostException */ - public Uploader( String ip, int port, SSLContext context ) + public Uploader( String host, int port, SSLContext context ) throws IOException { - try { - sslSocketFactory = context.getSocketFactory(); - - satelliteSocket = (SSLSocket)sslSocketFactory.createSocket( ip, port ); - satelliteSocket.setSoTimeout( 2000 ); // set socket timeout. - - dataToServer = new DataOutputStream( satelliteSocket.getOutputStream() ); - dataToServer.writeByte( 'U' ); - dataFromServer = new DataInputStream( satelliteSocket.getInputStream() ); - } catch ( Exception e ) { - e.printStackTrace(); - } + super( host, port, context, log ); + dataToServer.writeByte( 'U' ); } /***********************************************************************/ @@ -69,217 +37,23 @@ public class Uploader * * @throws IOException */ - public Uploader( SSLSocket socket ) - { - try { - satelliteSocket = socket; - dataToServer = new DataOutputStream( satelliteSocket.getOutputStream() ); - dataFromServer = new DataInputStream( satelliteSocket.getInputStream() ); - } catch ( IOException e ) { - e.printStackTrace(); - } - } - - /***********************************************************************/ - /** - * Method for sending token from satellite to master. - * Needfull for getting to know what should happens over connection. - * - * @param t - */ - public Boolean sendToken( String token ) - { - try { - TOKEN = token; - String sendToken = "TOKEN=" + TOKEN; - byte[] data = sendToken.getBytes( StandardCharsets.UTF_8 ); - dataToServer.writeByte( data.length ); - dataToServer.write( data ); - } catch ( SocketTimeoutException ste ) { - ste.printStackTrace(); - log.info( "Socket timeout occured ... close connection." ); - this.close(); - return false; - } catch ( IOException e ) { - e.printStackTrace(); - readMetaData(); - if ( ERROR != null ) { - if ( ERROR == "timeout" ) { - log.info( "Socket timeout occured ... close connection." ); - this.close(); - } - } - log.info( "Sending TOKEN in Uploader failed..." ); - return false; - } - return true; - } - - /***********************************************************************/ - /** - * Getter for TOKEN. - */ - public String getToken() + public Uploader( SSLSocket socket ) throws IOException { - return TOKEN; + super( socket, log ); } /***********************************************************************/ /** - * Method to send range of the file, which should be uploaded. - * Helpful for knowing how much was already uploaded if - * connection aborts. - * - * @param a - * @param b - */ - public Boolean sendRange( int a, int b ) - { - try { - RANGE = a + ":" + b; - String sendRange = "RANGE=" + RANGE; - byte[] data = sendRange.getBytes( StandardCharsets.UTF_8 ); - dataToServer.writeByte( data.length ); - dataToServer.write( data ); - dataToServer.writeByte( 0 ); - } catch ( SocketTimeoutException ste ) { - ste.printStackTrace(); - log.info( "Socket timeout occured ... close connection." ); - this.close(); - } catch ( IOException e ) { - e.printStackTrace(); - readMetaData(); - if ( ERROR != null ) { - if ( ERROR == "timeout" ) { - log.info( "Socket timeout occured ... close connection." ); - this.close(); - } - } - log.info( "Sending RANGE in Uploader failed..." ); - return false; - } - return true; - } - - /***********************************************************************/ - /** - * Getter for RANGE. + * Used by the peer that initiated the connection to tell the remote + * peer which part of the file is being uploaded * + * @param startOffset start offset in bytes in the file (inclusive) + * @param endOffset end offset in file (exclusive) * @return */ - public String getRange() + public boolean prepareSendRange( int startOffset, int endOffset ) { - return RANGE; - } - - /***********************************************************************/ - /** - * Getter for beginning of RANGE. - * - * @return - */ - public int getStartOfRange() - { - if ( RANGE != null ) { - String[] splitted = RANGE.split( ":" ); - return Integer.parseInt( splitted[0] ); - } - return -1; - } - - /***********************************************************************/ - /** - * Getter for end of RANGE. - * - * @return - */ - public int getEndOfRange() - { - if ( RANGE != null ) { - String[] splitted = RANGE.split( ":" ); - return Integer.parseInt( splitted[1] ); - } - return -1; - } - - /***********************************************************************/ - /** - * Method for returning difference of current Range. - * - * @return - */ - public int getDiffOfRange() - { - if ( getStartOfRange() == -1 || getEndOfRange() == -1 ) { - return -1; - } - int diff = Math.abs( getEndOfRange() - getStartOfRange() ); - return diff; - } - - /***********************************************************************/ - /** - * Method for reading MetaData, like TOKEN and FileRange. - * Split incoming bytes after first '=' and store value to specific - * variable. - * - */ - public Boolean readMetaData() - { - try { - while ( true ) { - byte[] incoming = new byte[ 255 ]; - - // First get length. - dataFromServer.read( incoming, 0, 1 ); - int length = incoming[0] & 0xFF; - - if ( length == 0 ) // Stop if 0 was read. - break; - - /** - * Read the next available bytes and split by '=' for - * getting TOKEN or RANGE. - */ - int hasRead = 0; - while ( hasRead < length ) { - int ret = dataFromServer.read( incoming, hasRead, length - hasRead ); - if ( ret == -1 ) { - log.info( "Error in reading Metadata occured!" ); - return false; - } - hasRead += ret; - } - String data = new String( incoming, "UTF-8" ); - - String[] splitted = data.split( "=" ); - if ( splitted[0] != null && splitted[0].equals( "TOKEN" ) ) { - if ( splitted[1] != null ) - TOKEN = splitted[1]; - log.info( "TOKEN: " + TOKEN ); - } - else if ( splitted[0].equals( "RANGE" ) ) { - if ( splitted[1] != null ) - RANGE = splitted[1]; - log.info( "RANGE: " + RANGE ); - } - else if ( splitted[0].equals( "ERROR" ) ) { - if ( splitted[1] != null ) - ERROR = splitted[1]; - log.info( "ERROR: " + ERROR ); - return false; - } - } - } catch ( SocketTimeoutException ste ) { - ste.printStackTrace(); - sendErrorCode( "timeout" ); - log.info( "Socket timeout occured ... close connection" ); - this.close(); - } catch ( Exception e ) { - e.printStackTrace(); - return false; - } - return true; + return super.sendRange( startOffset, endOffset ); } /***********************************************************************/ @@ -288,26 +62,28 @@ public class Uploader * * @param filename */ - public Boolean sendFile( String filename ) + public boolean sendFile( String filename ) { RandomAccessFile file = null; try { file = new RandomAccessFile( new File( filename ), "r" ); if ( getStartOfRange() == -1 ) { + this.close(); return false; } file.seek( getStartOfRange() ); - byte[] data = new byte[ 4000 ]; + byte[] data = new byte[ 64000 ]; int hasRead = 0; int length = getDiffOfRange(); -// System.out.println( "diff of Range: " + length ); + // System.out.println( "diff of Range: " + length ); while ( hasRead < length ) { int ret = file.read( data, 0, Math.min( length - hasRead, data.length ) ); if ( ret == -1 ) { - log.info( "Error occured in Uploader.sendFile()," + log.warn( "Error occured in Uploader.sendFile()," + " while reading from File to send." ); + this.close(); return false; } hasRead += ret; @@ -316,7 +92,7 @@ public class Uploader } catch ( SocketTimeoutException ste ) { ste.printStackTrace(); sendErrorCode( "timeout" ); - log.info( "Socket timeout occured ... close connection." ); + log.warn( "Socket timeout occured ... close connection." ); this.close(); return false; } catch ( IOException ioe ) { @@ -324,64 +100,27 @@ public class Uploader readMetaData(); if ( ERROR != null ) { if ( ERROR == "timeout" ) { - log.info( "Socket timeout occured ... close connection." ); + log.warn( "Socket timeout occured ... close connection." ); this.close(); } } - log.info( "Sending RANGE " + getStartOfRange() + ":" + getEndOfRange() + " of File " + log.warn( "Sending RANGE " + getStartOfRange() + ":" + getEndOfRange() + " of File " + filename + " failed..." ); + this.close(); return false; } catch ( Exception e ) { e.printStackTrace(); + this.close(); return false; } finally { - try { - file.close(); - } catch ( IOException e ) { + if ( file != null ) { + try { + file.close(); + } catch ( IOException e ) { + } } } return true; } - /***********************************************************************/ - /** - * Method for sending error Code to server. For example in case of wrong - * token, send code for wrong token. - * - */ - public Boolean sendErrorCode( String errString ) - { - try { - String sendError = "ERROR=" + errString; - byte[] data = sendError.getBytes( StandardCharsets.UTF_8 ); - dataToServer.writeByte( data.length ); - dataToServer.write( data ); - } catch ( IOException e ) { - e.printStackTrace(); - this.close(); - return false; - } - return true; - } - - /***********************************************************************/ - /** - * Method for closing connection, if upload has finished. - * - */ - public void close() - { - try { - if ( satelliteSocket != null ) { - this.satelliteSocket.close(); - satelliteSocket = null; - } - if ( dataFromServer != null ) - dataFromServer.close(); - if ( dataToServer != null ) - dataToServer.close(); - } catch ( IOException e ) { - e.printStackTrace(); - } - } } -- cgit v1.2.3-55-g7522