package org.dcache.ftp.data; import java.io.IOException; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; import org.dcache.pool.repository.RepositoryChannel; /** Implementation of MODE S. */ public class ModeS extends Mode { private final int _blockSize; /* Implements MODE S send operation. */ private class Sender extends AbstractMultiplexerListener { protected final SocketChannel _socket; protected long _position; protected long _count; public Sender(SocketChannel socket) { _socket = socket; _position = getStartPosition(); _count = getSize(); } @Override public void register(Multiplexer multiplexer) throws IOException { multiplexer.register(this, SelectionKey.OP_WRITE, _socket); } @Override public void write(Multiplexer multiplexer, SelectionKey key) throws IOException, FTPException { long nbytes = transferTo(_position, _count, _socket); _monitor.sentBlock(_position, nbytes); _position += nbytes; _count -= nbytes; /* There is no special end-of-file signal in mode S. Just * close the connection. */ if (_count == 0) { close(multiplexer, key, true); } } } /* Implements MODE S receive operation. */ private class Receiver extends AbstractMultiplexerListener { protected final SocketChannel _socket; protected long _position; public Receiver(SocketChannel socket) { _socket = socket; _position = 0; } @Override public void register(Multiplexer multiplexer) throws IOException { multiplexer.register(this, SelectionKey.OP_READ, _socket); } @Override public void read(Multiplexer multiplexer, SelectionKey key) throws IOException, InterruptedException, FTPException { _monitor.preallocate(_position + _blockSize); long nbytes = transferFrom(_socket, _position, _blockSize); if (nbytes == -1) { close(multiplexer, key, true); } else { _monitor.receivedBlock(_position, nbytes); _position += nbytes; } } } public ModeS(Role role, RepositoryChannel file, ConnectionMonitor monitor, int blockSize) throws IOException { super(role, file, monitor); _blockSize = blockSize; } @Override public void newConnection(Multiplexer multiplexer, SocketChannel socket) throws IOException { switch (_role) { case Sender: multiplexer.add(new Sender(socket)); break; case Receiver: multiplexer.add(new Receiver(socket)); break; } } }