summaryrefslogtreecommitdiffstats
path: root/src/main/java/org/openslx/filetransfer
diff options
context:
space:
mode:
authorSimon Rettberg2014-07-25 14:20:00 +0200
committerSimon Rettberg2014-07-25 14:20:00 +0200
commit036807ab4006bf81188e5324fa53e34b1c7d5ae6 (patch)
tree77c48ee55cb9973c6a594cd2fde1c212d543c45e /src/main/java/org/openslx/filetransfer
parent[CRCFile] Add checks to prevent null pointer exception (diff)
downloadmaster-sync-shared-036807ab4006bf81188e5324fa53e34b1c7d5ae6.tar.gz
master-sync-shared-036807ab4006bf81188e5324fa53e34b1c7d5ae6.tar.xz
master-sync-shared-036807ab4006bf81188e5324fa53e34b1c7d5ae6.zip
[Filetransfer] Add more sanity checks and error handling, remodel class structure, introduce common base class for Uploader and Downloader
Diffstat (limited to 'src/main/java/org/openslx/filetransfer')
-rw-r--r--src/main/java/org/openslx/filetransfer/ClassTest.java4
-rw-r--r--src/main/java/org/openslx/filetransfer/Downloader.java322
-rw-r--r--src/main/java/org/openslx/filetransfer/Listener.java20
-rw-r--r--src/main/java/org/openslx/filetransfer/Transfer.java327
-rw-r--r--src/main/java/org/openslx/filetransfer/Uploader.java327
5 files changed, 405 insertions, 595 deletions
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();
- }
- }
}