File Source: DCCSend.java

     1  /*
     2   * Copyright (c) 2006-2009 Chris Smith, Shane Mc Cormack, Gregory Holmes
     3   *
     4   * Permission is hereby granted, free of charge, to any person obtaining a copy
     5   * of this software and associated documentation files (the "Software"), to deal
     6   * in the Software without restriction, including without limitation the rights
     7   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     8   * copies of the Software, and to permit persons to whom the Software is
     9   * furnished to do so, subject to the following conditions:
    10   *
    11   * The above copyright notice and this permission notice shall be included in
    12   * all copies or substantial portions of the Software.
    13   *
    14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    20   * SOFTWARE.
    21   */
    22  
    23  package com.dmdirc.addons.dcc;
    24  
    25  import java.io.DataInputStream;
    26  import java.io.DataOutputStream;
    27  import java.io.File;
    28  import java.io.FileInputStream;
    29  import java.io.FileOutputStream;
    30  import java.io.IOException;
    31  import java.io.FileNotFoundException;
    32  import java.util.ArrayList;
    33  import java.util.List;
    34  
    35  /**
    36   * This class handles a DCC Send.
    37   *
    38   * @author Shane 'Dataforce' McCormack
    39   */
    40  public class DCCSend extends DCC {
    41  	/** List of active sends. */
        	 /* 
    P/P 	  *  Method: com.dmdirc.addons.dcc.DCCSend__static_init
        	  * 
        	  *  Postconditions:
        	  *    SENDS == &new ArrayList(DCCSend__static_init#1)
        	  *    new ArrayList(DCCSend__static_init#1) num objects == 1
        	  */
    42  	private static final List<DCCSend> SENDS = new ArrayList<DCCSend>();
    43  	
    44  	/** File Transfer Types. */
        	 /* 
    P/P 	  *  Method: com.dmdirc.addons.dcc.DCCSend$TransferType__static_init
        	  * 
        	  *  Postconditions:
        	  *    $VALUES == &amp;new DCCSend$TransferType[](DCCSend$TransferType__static_init#3)
        	  *    RECEIVE == &amp;new DCCSend$TransferType(DCCSend$TransferType__static_init#2)
        	  *    $VALUES[1] == &amp;new DCCSend$TransferType(DCCSend$TransferType__static_init#2)
        	  *    SEND == &amp;new DCCSend$TransferType(DCCSend$TransferType__static_init#1)
        	  *    $VALUES[0] == &amp;new DCCSend$TransferType(DCCSend$TransferType__static_init#1)
        	  *    new DCCSend$TransferType(DCCSend$TransferType__static_init#1) num objects == 1
        	  *    new DCCSend$TransferType(DCCSend$TransferType__static_init#2) num objects == 1
        	  *    new DCCSend$TransferType[](DCCSend$TransferType__static_init#3) num objects == 1
        	  *    $VALUES.length == 2
        	  */
    45  	public enum TransferType { SEND, RECEIVE; }
    46  	/** The File transfer type for this file. */
    47  	private TransferType transferType = TransferType.RECEIVE;
    48  	/** The handler for this DCCSend. */
    49  	private DCCSendInterface handler;
    50  	/** Used to send data out the socket. */
    51  	private DataOutputStream out;
    52  	/** Used to read data from the socket. */
    53  	private DataInputStream in;
    54  	/** File we are using. */
    55  	private File transferFile;
    56  	/** Used to write data to the file. */
    57  	private DataOutputStream fileOut;
    58  	/** Used to read data from the file. */
    59  	private DataInputStream fileIn;
    60  	/** Where are we starting from? */
    61  	private int startpos;
    62  	/** How big is this file? */
    63  	private long size = -1;
    64  	/** How much of this file have we read so far? */
    65  	private long readSize;
    66  	/** What is the name of the file? */
    67  	private String filename = "";
    68  	/** What is the token for this send? */
    69  	private String token = "";
    70  	/** Block Size. */
    71  	private final int blockSize;
    72  	/** Is this a turbo dcc? */
    73  	private boolean turbo = false;
    74  	
    75  	/** Creates a new instance of DCCSend with a default block size. */
    76  	public DCCSend() {
        		 /* 
    P/P 		  *  Method: void com.dmdirc.addons.dcc.DCCSend()
        		  * 
        		  *  Postconditions:
        		  *    this.address == 0
        		  *    this.listen == 0
        		  *    this.port == 0
        		  *    this.running == 0
        		  *    this.turbo == 0
        		  *    this.blockSize == 1_024
        		  *    this.filename == &amp;""
        		  *    this.token == &amp;""
        		  *    this.serverListeningSem == &amp;new Semaphore(DCC#2)
        		  *    this.serverSocketSem == &amp;new Semaphore(DCC#1)
        		  *    ...
        		  */
    77  		this(1024);
    78  	}
    79  	
    80  	/**
    81  	 * Creates a new instance of DCCSend.
    82  	 *
    83  	 * @param blockSize Block size to use
    84  	 */
    85  	public DCCSend(final int blockSize) {
        		 /* 
    P/P 		  *  Method: void com.dmdirc.addons.dcc.DCCSend(int)
        		  * 
        		  *  Postconditions:
        		  *    this.address == 0
        		  *    this.listen == 0
        		  *    this.port == 0
        		  *    this.running == 0
        		  *    this.turbo == 0
        		  *    this.blockSize == blockSize
        		  *    init'ed(this.blockSize)
        		  *    this.filename == &amp;""
        		  *    this.token == &amp;""
        		  *    this.serverListeningSem == &amp;new Semaphore(DCC#2)
        		  *    ...
        		  */
    86  		super();
    87  		this.blockSize = blockSize;
    88  		synchronized (SENDS) {
    89  			SENDS.add(this);
    90  		}
    91  	}
    92  	
    93  	/**
    94  	 * Reset this send to be used again (eg a resend).
    95  	 */
    96  	public void reset() {
        		 /* 
    P/P 		  *  Method: void reset()
        		  * 
        		  *  Preconditions:
        		  *    init'ed(this.filename)
        		  *    init'ed(this.startpos)
        		  *    this.serverSocketSem != null
        		  *    init'ed(this.transferType)
        		  *    (soft) init'ed(this.fileIn)
        		  *    (soft) init'ed(this.serverSocket)
        		  *    (soft) init'ed(this.socket)
        		  *    (soft) this.serverListeningSem != null
        		  * 
        		  *  Postconditions:
        		  *    this.fileIn == One-of{old this.fileIn, &amp;new DataInputStream(setFileName#2), null}
        		  *    init'ed(this.fileIn)
        		  *    this.filename == old this.filename
        		  *    init'ed(this.filename)
        		  *    possibly_updated(this.in)
        		  *    possibly_updated(this.out)
        		  *    this.readSize == One-of{old this.startpos, old this.readSize}
        		  *    this.serverSocket == null
        		  *    this.socket == null
        		  *    init'ed(this.startpos)
        		  *    ...
        		  */
    97  		close();
    98  		setFileName(filename);
    99  		setFileStart(startpos);
   100  	}
   101  	
   102  	/**
   103  	 * Get a copy of the list of active sends.
   104  	 *
   105  	 * @return A copy of the list of active sends.
   106  	 */
   107  	public static List<DCCSend> getSends() {
        		 /* 
    P/P 		  *  Method: List getSends()
        		  * 
        		  *  Postconditions:
        		  *    return_value == &amp;new ArrayList(getSends#1)
        		  *    new ArrayList(getSends#1) num objects == 1
        		  */
   108  		synchronized (SENDS) {
   109  			return new ArrayList<DCCSend>(SENDS);
   110  		}
   111  	}
   112  	
   113  	/**
   114  	 * Called to remove this object from the sends list.
   115  	 */
   116  	public void removeFromSends() {
        		 /* 
    P/P 		  *  Method: void removeFromSends()
        		  */
   117  		synchronized (SENDS) {
   118  			SENDS.remove(this);
   119  		}
   120  	}
   121  	
   122  	/**
   123  	 * Set the filename of this file
   124  	 *
   125  	 * @param filename Filename
   126  	 */
   127  	public void setFileName(final String filename) {
        		 /* 
    P/P 		  *  Method: void setFileName(String)
        		  * 
        		  *  Preconditions:
        		  *    init'ed(this.transferType)
        		  * 
        		  *  Postconditions:
        		  *    this.fileIn == One-of{old this.fileIn, &amp;new DataInputStream(setFileName#2), null}
        		  *    this.filename == filename
        		  *    init'ed(this.filename)
        		  *    this.transferFile == One-of{old this.transferFile, &amp;new File(setFileName#1)}
        		  *    new DataInputStream(setFileName#2) num objects <= 1
        		  *    new File(setFileName#1) num objects <= 1
        		  */
   128  		this.filename = filename;
   129  		if (transferType == TransferType.SEND) {
   130  			transferFile = new File(filename);
   131  			try {
   132  				fileIn = new DataInputStream(new FileInputStream(transferFile.getAbsolutePath()));
   133  			} catch (FileNotFoundException e) {
   134  				fileIn = null;
   135  			} catch (SecurityException e) {
   136  				fileIn = null;
   137  			}
   138  		}
   139  	}
   140  	
   141  	/**
   142  	 * Get the filename of this file
   143  	 *
   144  	 * @return Filename
   145  	 */
   146  	public String getFileName() {
        		 /* 
    P/P 		  *  Method: String getFileName()
        		  * 
        		  *  Preconditions:
        		  *    init'ed(this.filename)
        		  * 
        		  *  Postconditions:
        		  *    return_value == this.filename
        		  *    init'ed(return_value)
        		  */
   147  		return filename;
   148  	}
   149  	
   150  	/**
   151  	 * Get the filename of this file, without the path
   152  	 *
   153  	 * @return Filename without path
   154  	 */
   155  	public String getShortFileName() {
        		 /* 
    P/P 		  *  Method: String getShortFileName()
        		  * 
        		  *  Preconditions:
        		  *    init'ed(this.filename)
        		  * 
        		  *  Postconditions:
        		  *    init'ed(return_value)
        		  */
   156  		return (new File(filename)).getName();
   157  	}
   158  	
   159  	/**
   160  	 * Set dcc Type.
   161  	 *
   162  	 * @param type Type of DCC Send this is.
   163  	 */
   164  	public void setType(final TransferType type) {
        		 /* 
    P/P 		  *  Method: void setType(DCCSend$TransferType)
        		  * 
        		  *  Postconditions:
        		  *    this.transferType == type
        		  *    init'ed(this.transferType)
        		  */
   165  		this.transferType = type;
   166  	}
   167  	
   168  	/**
   169  	 * Get dcc Type.
   170  	 *
   171  	 * @return Type of DCC Send this is.
   172  	 */
   173  	public TransferType getType() {
        		 /* 
    P/P 		  *  Method: DCCSend$TransferType getType()
        		  * 
        		  *  Preconditions:
        		  *    init'ed(this.transferType)
        		  * 
        		  *  Postconditions:
        		  *    return_value == this.transferType
        		  *    init'ed(return_value)
        		  */
   174  		return transferType;
   175  	}
   176  	
   177  	/**
   178  	 * Set turbo mode on/off.
   179  	 * Turbo mode doesn't wait for ack packets. Only relevent when sending.
   180  	 *
   181  	 * @param turbo True for turbo dcc, else false
   182  	 */
   183  	public void setTurbo(final boolean turbo) {
        		 /* 
    P/P 		  *  Method: void setTurbo(bool)
        		  * 
        		  *  Postconditions:
        		  *    this.turbo == turbo
        		  *    init'ed(this.turbo)
        		  */
   184  		this.turbo = turbo;
   185  	}
   186  	
   187  	/**
   188  	 * Is turbo mode on/off.
   189  	 * Turbo mode doesn't wait for ack packets. Only relevent when sending.
   190  	 *
   191  	 * @return True for turbo dcc, else false
   192  	 */
   193  	public boolean isTurbo() {
        		 /* 
    P/P 		  *  Method: bool isTurbo()
        		  * 
        		  *  Preconditions:
        		  *    init'ed(this.turbo)
        		  * 
        		  *  Postconditions:
        		  *    return_value == this.turbo
        		  *    init'ed(return_value)
        		  */
   194  		return turbo;
   195  	}
   196  	
   197  	/**
   198  	 * Set the Token for this send
   199  	 *
   200  	 * @param token Token for this send
   201  	 */
   202  	public void setToken(final String token) {
        		 /* 
    P/P 		  *  Method: void setToken(String)
        		  * 
        		  *  Postconditions:
        		  *    this.token == token
        		  *    init'ed(this.token)
        		  */
   203  		this.token = token;
   204  	}
   205  	
   206  	/**
   207  	 * Get the Token for this send
   208  	 *
   209  	 * @return Token for this send
   210  	 */
   211  	public String getToken() {
        		 /* 
    P/P 		  *  Method: String getToken()
        		  * 
        		  *  Preconditions:
        		  *    init'ed(this.token)
        		  * 
        		  *  Postconditions:
        		  *    return_value == this.token
        		  *    init'ed(return_value)
        		  */
   212  		return token;
   213  	}
   214  	
   215  	/**
   216  	 * Make a Token for this send.
   217  	 * This token will be unique compared to all the other known sends
   218  	 *
   219  	 * @return The Token for this send.
   220  	 */
   221  	public String makeToken() {
        		 /* 
    P/P 		  *  Method: String makeToken()
        		  * 
        		  *  Preconditions:
        		  *    init'ed(this.filename)
        		  * 
        		  *  Postconditions:
        		  *    java.lang.Integer:toString(...)._tainted == 0
        		  *    return_value == &amp;java.lang.Integer:toString(...)
        		  *    this.token == &amp;java.lang.Integer:toString(...)
        		  */
   222  		String myToken = "";
   223  		boolean unique = true;
   224  		do {
   225  			myToken = Integer.toString(Math.abs((myToken+filename).hashCode()));
   226  			unique = (findByToken(myToken) == null);
   227  		} while (!unique);
   228  		setToken(myToken);
   229  		return myToken;
   230  	}
   231  	
   232  	/**
   233  	 * Find a send based on a given token.
   234  	 *
   235  	 * @param token Token to look for. (case sensitive)
   236  	 * @return The first DCCSend that matches the given token.
   237  	 *         null if none match, or token is "" or null.
   238  	 */
   239  	public static DCCSend findByToken(final String token) {
        		 /* 
    P/P 		  *  Method: DCCSend findByToken(String)
        		  * 
        		  *  Presumptions:
        		  *    java.util.Iterator:next(...)@241 != null
        		  *    send.token@241 != null
        		  * 
        		  *  Postconditions:
        		  *    init'ed(return_value)
        		  * 
        		  *  Test Vectors:
        		  *    token: Addr_Set{null}, Inverse{null}
        		  *    java.lang.String:equals(...)@242: {0}, {1}
        		  *    java.lang.String:isEmpty(...)@240: {0}, {1}
        		  *    java.util.Iterator:hasNext(...)@241: {0}, {1}
        		  */
   240  		if (token == null || token.isEmpty()) { return null; }
   241  		for (DCCSend send : getSends()) {
   242  			if (send.getToken().equals(token)) {
   243  				return send;
   244  			}
   245  		}
   246  		return null;
   247  	}
   248  	
   249  	/**
   250  	 * Set the size of the file
   251  	 *
   252  	 * @param size File size
   253  	 */
   254  	public void setFileSize(final long size) {
        		 /* 
    P/P 		  *  Method: void setFileSize(long)
        		  * 
        		  *  Postconditions:
        		  *    this.size == size
        		  *    init'ed(this.size)
        		  */
   255  		this.size = size;
   256  	}
   257  	
   258  	/**
   259  	 * Get the expected size of the file
   260  	 *
   261  	 * @return The expected File size (-1 if unknown)
   262  	 */
   263  	public long getFileSize() {
        		 /* 
    P/P 		  *  Method: long getFileSize()
        		  * 
        		  *  Preconditions:
        		  *    init'ed(this.size)
        		  * 
        		  *  Postconditions:
        		  *    return_value == this.size
        		  *    init'ed(return_value)
        		  */
   264  		return size;
   265  	}
   266  	
   267  	/**
   268  	 * Set the starting position of the file
   269  	 *
   270  	 * @param startpos Starting position
   271  	 * @return -1 if fileIn is null or if dcc receive, else the result of fileIn.skipBytes()
   272  	 */
   273  	public int setFileStart(final int startpos) {
        		 /* 
    P/P 		  *  Method: int setFileStart(int)
        		  * 
        		  *  Preconditions:
        		  *    init'ed(this.transferType)
        		  *    (soft) init'ed(this.fileIn)
        		  * 
        		  *  Postconditions:
        		  *    init'ed(return_value)
        		  *    this.readSize == One-of{startpos, old this.readSize}
        		  *    init'ed(this.startpos)
        		  * 
        		  *  Test Vectors:
        		  *    this.fileIn: Addr_Set{null}, Inverse{null}
        		  */
   274  		this.startpos = startpos;
   275  		if (transferType == TransferType.SEND && fileIn != null) {
   276  			try {
   277  				this.startpos = fileIn.skipBytes(startpos);
   278  				readSize = startpos;
   279  				return this.startpos;
   280  			} catch (IOException ioe) { }
   281  		}
   282  		return -1;
   283  	}
   284  	
   285  	/**
   286  	 * Get the starting position of the file
   287  	 *
   288  	 * @return starting position of file.
   289  	 */
   290  	public int getFileStart() {
        		 /* 
    P/P 		  *  Method: int getFileStart()
        		  * 
        		  *  Preconditions:
        		  *    init'ed(this.startpos)
        		  * 
        		  *  Postconditions:
        		  *    return_value == this.startpos
        		  *    init'ed(return_value)
        		  */
   291  		return this.startpos;
   292  	}
   293  	
   294  	/**
   295  	 * Change the handler for this DCC Send
   296  	 *
   297  	 * @param handler A class implementing DCCSendInterface
   298  	 */
   299  	public void setHandler(final DCCSendInterface handler) {
        		 /* 
    P/P 		  *  Method: void setHandler(DCCSendInterface)
        		  * 
        		  *  Postconditions:
        		  *    this.handler == handler
        		  *    init'ed(this.handler)
        		  */
   300  		this.handler = handler;
   301  	}
   302  	
   303  	/**
   304  	 * Called when the socket is first opened, before any data is handled.
   305  	 */
   306  	@Override
   307  	protected void socketOpened() {
   308  		try {
        			 /* 
    P/P 			  *  Method: void socketOpened()
        			  * 
        			  *  Preconditions:
        			  *    init'ed(this.handler)
        			  *    (soft) init'ed(this.in)
        			  *    (soft) init'ed(this.out)
        			  *    (soft) init'ed(this.filename)
        			  *    (soft) this.socket != null
        			  *    (soft) init'ed(this.startpos)
        			  *    (soft) init'ed(this.transferType)
        			  * 
        			  *  Postconditions:
        			  *    this.fileOut == One-of{old this.fileOut, &amp;new DataOutputStream(socketOpened#2)}
        			  *    this.handler.timeStarted == old this.handler.timeStarted
        			  *    this.in in Addr_Set{null,&amp;new DataInputStream(socketOpened#5)}
        			  *    this.out in Addr_Set{null,&amp;new DataOutputStream(socketOpened#4)}
        			  *    this.transferFile == One-of{&amp;new File(socketOpened#1), old this.transferFile}
        			  *    new DataInputStream(socketOpened#5) num objects <= 1
        			  *    new DataOutputStream(socketOpened#2) num objects <= 1
        			  *    new DataOutputStream(socketOpened#4) num objects <= 1
        			  *    new File(socketOpened#1) num objects <= 1
        			  * 
        			  *  Test Vectors:
        			  *    this.handler: Addr_Set{null}, Inverse{null}
        			  */
   309  			transferFile = new File(filename);
   310  			if (transferType == TransferType.RECEIVE) {
   311  				fileOut = new DataOutputStream(new FileOutputStream(transferFile.getAbsolutePath(), (startpos > 0)));
   312  			}
   313  			out = new DataOutputStream(socket.getOutputStream());
   314  			in = new DataInputStream(socket.getInputStream());
   315  			if (handler != null) {
   316  				handler.socketOpened(this);
   317  			}
   318  		} catch (IOException ioe) {
   319              socketClosed();
   320          }
   321  	}
   322  	
   323  	/**
   324  	 * Called when the socket is closed, before the thread terminates.
   325  	 */
   326  	@Override
   327  	protected void socketClosed() {
   328  		// Try to close both, even if one fails.
        		 /* 
    P/P 		  *  Method: void socketClosed()
        		  * 
        		  *  Preconditions:
        		  *    init'ed(this.in)
        		  *    init'ed(this.out)
        		  *    init'ed(this.handler)
        		  * 
        		  *  Postconditions:
        		  *    this.in == null
        		  *    this.out == null
        		  * 
        		  *  Test Vectors:
        		  *    this.in: Addr_Set{null}, Inverse{null}
        		  *    this.out: Addr_Set{null}, Inverse{null}
        		  *    this.handler: Addr_Set{null}, Inverse{null}
        		  */
   329  		if (out != null) { try { out.close(); } catch (IOException e) { } }
   330  		if (in != null) { try { in.close(); } catch (IOException e) { } }
   331  		out = null;
   332  		in = null;
   333  		if (handler != null) {
   334  			handler.socketClosed(this);
   335  		}
   336  		synchronized (SENDS) {
   337  			SENDS.remove(this);
   338  		}
   339  	}
   340  	
   341  	/**
   342  	 * Handle the socket.
   343  	 *
   344  	 * @return false when socket is closed, true will cause the method to be
   345  	 *         called again.
   346  	 */
   347  	@Override
   348  	protected boolean handleSocket() {
        		 /* 
    P/P 		  *  Method: bool handleSocket()
        		  * 
        		  *  Preconditions:
        		  *    init'ed(this.out)
        		  *    (soft) this.readSize in {-6_442_450_943..6_442_450_943}
        		  *    (soft) this.blockSize >= 0
        		  *    (soft) this.fileIn != null
        		  *    (soft) this.fileOut != null
        		  *    (soft) init'ed(this.handler)
        		  *    (soft) init'ed(this.in)
        		  *    (soft) init'ed(this.size)
        		  *    (soft) init'ed(this.transferType)
        		  *    (soft) init'ed(this.turbo)
        		  * 
        		  *  Postconditions:
        		  *    init'ed(return_value)
        		  *    possibly_updated(this.handler.transferCount)
        		  *    init'ed(this.readSize)
        		  * 
        		  *  Test Vectors:
        		  *    this.in: Inverse{null}, Addr_Set{null}
        		  *    this.out: Addr_Set{null}, Inverse{null}
        		  */
   349  		if (out == null || in == null) { return false; }	
   350  		if (transferType == TransferType.RECEIVE) {
   351  			return handleReceive();
   352  		} else {
   353  			return handleSend();
   354  		}
   355  	}
   356  	
   357  	
   358  	/**
   359  	 * Handle the socket as a RECEIVE.
   360  	 *
   361  	 * @return false when socket is closed (or should be closed), true will cause the method to be
   362  	 *         called again.
   363  	 */
   364  	protected boolean handleReceive() {
   365  		try {
        			 /* 
    P/P 			  *  Method: bool handleReceive()
        			  * 
        			  *  Preconditions:
        			  *    (soft) this.readSize in {-6_442_450_943..6_442_450_943}
        			  *    (soft) this.blockSize >= 0
        			  *    (soft) this.fileOut != null
        			  *    (soft) init'ed(this.handler)
        			  *    (soft) this.in != null
        			  *    (soft) this.out != null
        			  *    (soft) init'ed(this.size)
        			  * 
        			  *  Presumptions:
        			  *    this.readSize + java.io.DataInputStream:read(...)@367 in {-231..232-1}
        			  * 
        			  *  Postconditions:
        			  *    init'ed(return_value)
        			  *    this.handler.transferCount == old this.handler.transferCount
        			  *    this.readSize in {-6_442_450_943..6_442_450_943}
        			  * 
        			  *  Test Vectors:
        			  *    this.handler: Addr_Set{null}, Inverse{null}
        			  *    java.io.DataInputStream:read(...)@367: {0}, {1..232-1}, {-231..-1}
        			  */
   366  			final byte[] data = new byte[blockSize];
   367  			final int bytesRead = in.read(data);
   368  			readSize = readSize + bytesRead;
   369  			
   370  			if (bytesRead > 0) {
   371  				if (handler != null) { handler.dataTransfered(this, bytesRead); }
   372  				fileOut.write(data, 0, bytesRead);
   373  				// Send ack
   374  				out.writeInt((int)readSize);
   375  				out.flush();
   376  				if (readSize == size) {
   377  					fileOut.close();
   378  					return false;
   379  				} else {
   380  					return true;
   381  				}
   382  			} else if (bytesRead < 0) {
   383  				fileOut.close();
   384  				return false;
   385  			}
   386  		} catch (IOException e) {
   387  			return false;
   388  		}
   389  		return false;
   390  	}
   391  	
   392  	/**
   393  	 * Handle the socket as a SEND.
   394  	 *
   395  	 * @return false when socket is closed (or should be closed), true will cause the method to be
   396  	 *         called again.
   397  	 */
   398  	protected boolean handleSend() {
   399  		try {
        			 /* 
    P/P 			  *  Method: bool handleSend()
        			  * 
        			  *  Preconditions:
        			  *    (soft) init'ed(this.readSize)
        			  *    (soft) this.blockSize >= 0
        			  *    (soft) this.fileIn != null
        			  *    (soft) init'ed(this.handler)
        			  *    (soft) this.in != null
        			  *    (soft) this.out != null
        			  *    (soft) init'ed(this.size)
        			  *    (soft) init'ed(this.turbo)
        			  * 
        			  *  Presumptions:
        			  *    this.readSize + java.io.DataInputStream:read(...)@401 in {-263..264-1}
        			  * 
        			  *  Postconditions:
        			  *    init'ed(return_value)
        			  *    this.handler.transferCount == old this.handler.transferCount
        			  *    init'ed(this.readSize)
        			  * 
        			  *  Test Vectors:
        			  *    this.handler: Addr_Set{null}, Inverse{null}
        			  *    this.turbo: {1}, {0}
        			  *    java.io.DataInputStream:read(...)@401: {0}, {1..232-1}, {-231..-1}
        			  *    java.io.DataInputStream:readInt(...)@429: {-231..0}, {1..232-1}
        			  */
   400  			final byte[] data = new byte[blockSize];
   401  			int bytesRead = fileIn.read(data);
   402  			readSize = readSize + bytesRead;
   403  			
   404  			if (bytesRead > 0) {
   405  				if (handler != null) { handler.dataTransfered(this, bytesRead); }
   406  				out.write(data, 0, bytesRead);
   407  				out.flush();
   408  				
   409  				// Wait for acknowlegement packet.
   410  				if (!turbo) {
   411  					int bytesRecieved;
   412  					do {
   413  						bytesRecieved = in.readInt();
   414  					} while ((readSize - bytesRecieved) > 0);
   415  				}
   416  				
   417  				if (readSize == size) {
   418  					fileIn.close();
   419  					
   420  					// Process all the ack packets that may have been sent.
   421  					// In true turbo dcc mode, none will have been sent and the socket
   422  					// will just close, in fast-dcc mode all the acks will be here,
   423  					// So keep reading acks untill the socket closes (IOException) or we
   424  					// have recieved all the acks.
   425  					if (turbo) {
   426  						int ack = 0;
   427  						do {
   428  							try {
   429  								ack = in.readInt();
   430  							} catch (IOException e) {
   431  								break;
   432  							}
   433  						} while (ack > 0 && (readSize - ack) > 0);
   434  					}
   435  					
   436  					return false;
   437  				}
   438  				
   439  				return true;
   440  			} else if (bytesRead < 0) {
   441  				fileIn.close();
   442  				return true;
   443  			}
   444  		} catch (IOException e) {
   445  			return false;
   446  		}
   447  		return false;
   448  	}
   449  }








SofCheck Inspector Build Version : 2.17854
DCCSend.java 2009-Jun-25 01:54:24
DCCSend.class 2009-Sep-02 17:04:14
DCCSend$TransferType.class 2009-Sep-02 17:04:14