package org.dcache.pool.movers; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.EOFException; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; import java.nio.ByteBuffer; import java.nio.channels.ClosedByInterruptException; import java.nio.channels.SocketChannel; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Map; import java.util.UUID; import diskCacheV111.util.CacheException; import diskCacheV111.util.ChecksumFactory; import diskCacheV111.util.DCapProrocolChallenge; import diskCacheV111.util.DiskErrorCacheException; import diskCacheV111.util.PnfsId; import diskCacheV111.vehicles.DCapProtocolInfo; import diskCacheV111.vehicles.PoolPassiveIoFileMessage; import diskCacheV111.vehicles.ProtocolInfo; import diskCacheV111.vehicles.StorageInfo; import dmg.cells.nucleus.CellArgsAware; import dmg.cells.nucleus.CellEndpoint; import dmg.cells.nucleus.CellMessage; import dmg.cells.nucleus.CellPath; import org.dcache.net.ProtocolConnectionPool; import org.dcache.net.ProtocolConnectionPool.Listen; import org.dcache.net.ProtocolConnectionPoolFactory; import org.dcache.pool.repository.Allocator; import org.dcache.pool.repository.RepositoryChannel; import org.dcache.util.Args; import org.dcache.util.Checksum; import org.dcache.util.ChecksumType; import org.dcache.util.NetworkUtils; import org.dcache.vehicles.FileAttributes; import static org.dcache.util.ByteUnit.KiB; import static org.dcache.util.ByteUnit.MiB; public class DCapProtocol_3_nio implements MoverProtocol, ChecksumMover, CellArgsAware { private static Logger _log = LoggerFactory.getLogger(DCapProtocol_3_nio.class); private static Logger _logSocketIO = LoggerFactory.getLogger("logger.dev.org.dcache.io.socket"); private static final Logger _logSpaceAllocation = LoggerFactory.getLogger("logger.dev.org.dcache.poolspacemonitor." + DCapProtocol_3_nio.class.getName()); private static final int INC_SPACE = MiB.toBytes(50); /** * Max request size that client sent by client that we will accept. */ private static final long MAX_REQUEST_SIZE = MiB.toBytes(8); private final Map<String,Object> _context; private final CellEndpoint _cell; private Args _args; private long _bytesTransferred = -1; private long _transferStarted; private long _transferTime = -1; private long _lastTransferred = System.currentTimeMillis(); private ByteBuffer _bigBuffer; private String _status = "None"; private boolean _io_ok = true; private long _ioError = -1; private PnfsId _pnfsId; private int _sessionId = -1; private Checksum _clientChecksum; private ChecksumFactory _checksumFactory; private MessageDigest _digest; private final MoverIoBuffer _defaultBufferSize = new MoverIoBuffer(KiB.toBytes(256), KiB.toBytes(256), KiB.toBytes(256)); private final MoverIoBuffer _maxBufferSize = new MoverIoBuffer(MiB.toBytes(1), MiB.toBytes(1), MiB.toBytes(1)); private SpaceMonitorHandler _spaceMonitorHandler; // bind passive dcap to port defined as org.dcache.dcap.port private static ProtocolConnectionPoolFactory factory; static { int port = 0; try { port = Integer.parseInt(System.getProperty("org.dcache.dcap.port")); }catch(NumberFormatException e){ /* bad values are ignored */} factory = new ProtocolConnectionPoolFactory(port, new DCapChallengeReader()); } private void initialiseBuffer(MoverIoBuffer bufferSize) { try { _bigBuffer = _bigBuffer == null ? ByteBuffer.allocate(bufferSize.getIoBufferSize()) : _bigBuffer; } catch (OutOfMemoryError om) { _bigBuffer = ByteBuffer.allocate(KiB.toBytes(32)); } } private MoverIoBuffer prepareBufferSize(StorageInfo storage) { MoverIoBuffer bufferSize = new MoverIoBuffer(_defaultBufferSize); String tmp; try { tmp = storage.getKey("send"); if (tmp != null) { bufferSize.setSendBufferSize(Math.min(Integer.parseInt(tmp), _maxBufferSize.getSendBufferSize())); } } catch (NumberFormatException e) { /* bad values are ignored */ } try { tmp = storage.getKey("receive"); if (tmp != null) { bufferSize.setRecvBufferSize(Math.min(Integer.parseInt(tmp), _maxBufferSize.getRecvBufferSize())); } } catch (NumberFormatException e) { /* bad values are ignored */ } try { tmp = storage.getKey("bsize"); if (tmp != null) { bufferSize.setIoBufferSize(Math.min(Integer.parseInt(tmp), _maxBufferSize.getIoBufferSize())); } } catch (NumberFormatException e) { /* bad values are ignored */ } return bufferSize; } @Override public void setCellArgs(Args args) { _args = args; } private class SpaceMonitorHandler { private final Allocator _allocator; private long _spaceAllocated; private long _allocationSpace = INC_SPACE; private long _spaceUsed; private SpaceMonitorHandler(Allocator allocator){ _allocator = allocator; } private void setAllocationSpace(long allocSpace){ _allocationSpace = allocSpace; } private void setInitialSpace(long space){ _spaceAllocated = space; _spaceUsed = space; } @Override public String toString(){ return "{a="+_spaceAllocated+";u="+_spaceUsed+"}"; } private void getSpace(long newEof) throws InterruptedException{ if (_allocator == null) { return; } while(newEof > _spaceAllocated){ _status = "WaitingForSpace("+_allocationSpace+")"; _log.debug("Allocating new space : {}", _allocationSpace); _logSpaceAllocation.debug("ALLOC: {} : {}", _pnfsId, _allocationSpace); _allocator.allocate(_allocationSpace); _spaceAllocated += _allocationSpace; _log.debug("Allocated new space : {}", _allocationSpace); _status = ""; } } private void newFilePosition(long newPosition){ _spaceUsed = Math.max(newPosition, _spaceUsed); } } // // helper class to use nio channels for input requests. // private static class RequestBlock { private ByteBuffer _buffer; private int _commandSize; private int _commandCode; private RequestBlock(){ _buffer = ByteBuffer.allocate(64); } private void read(SocketChannel channel) throws Exception { _commandSize = _commandCode = 0; _buffer.clear().limit(4); fillBuffer(channel); _buffer.rewind(); _commandSize = _buffer.getInt(); if (_commandSize < 4) { throw new CacheException(44, "Protocol Violation (cl<4)"); } if (_commandSize > _buffer.capacity()) { if (_commandSize > MAX_REQUEST_SIZE) { /* * well, protocol tells nothing about command block size limit (my bad). * but we will send "protocol violation" to indicate client that we cant handle it. */ _log.warn("Command size excided command block size : {}/{}", _commandSize, MAX_REQUEST_SIZE); // eat the data to keep TCP send buffer on the client side happy int n = 0; while (n < _commandSize) { _buffer.clear(); n += channel.read(_buffer); } throw new CacheException(44, "Protocol Violation: request block too big (" + _commandSize + ")"); } _log.info("Growing command block size from: {} to: {}", _buffer.capacity(), _commandSize); // we don't need any cind of synchronization as mover single threaded. _buffer = ByteBuffer.allocate(_commandSize); } _buffer.clear().limit(_commandSize); fillBuffer(channel); _buffer.rewind(); _commandCode = _buffer.getInt(); } private int remaining(){ return _buffer.remaining(); } private int getCommandCode(){ return _commandCode; } private int nextInt(){ return _buffer.getInt(); } private long nextLong(){ return _buffer.getLong(); } private void fillBuffer( SocketChannel channel) throws Exception{ while(_buffer.hasRemaining()){ if(channel.read(_buffer) < 0) { throw new EOFException("EOF on input socket (fillBuffer)"); } } } private void skip(int skip){ _buffer.position(_buffer.position()+skip); } private void get(byte [] array){ _buffer.get(array); } @Override public String toString(){ return "RequestBlock [Size="+_commandSize+ " Code="+_commandCode+ " Buffer="+_buffer; } } public DCapProtocol_3_nio(CellEndpoint cell){ _cell = cell; _context = _cell.getDomainContext(); // _log.info("DCapProtocol_3 (nio) created $Id: DCapProtocol_3_nio.java,v 1.17 2007-10-02 13:35:52 tigran Exp $"); } private void configureBufferSizes() { // // we are created for each request. So our data // is not shared. // _defaultBufferSize.setBufferSize( getParameterInt("defaultSendBufferSize", _defaultBufferSize.getSendBufferSize()), getParameterInt("defaultRecvBufferSize", _defaultBufferSize.getRecvBufferSize()), getParameterInt("defaultIoBufferSize" , _defaultBufferSize.getIoBufferSize()) ); _maxBufferSize.setBufferSize( getParameterInt("maxSendBufferSize", _maxBufferSize.getSendBufferSize()), getParameterInt("maxRecvBufferSize", _maxBufferSize.getRecvBufferSize()), getParameterInt("maxIoBufferSize" , _maxBufferSize.getIoBufferSize()) ); _log.info("Setup : Defaults Buffer Sizes : {}", _defaultBufferSize); _log.info("Setup : Max Buffer Sizes : {}", _maxBufferSize); } private synchronized int getParameterInt(String name, int defaultValue){ String stringValue = (String)_context.get("dCap3-"+name); stringValue = stringValue == null ? _args.getOpt(name) : stringValue; try{ return stringValue == null ? defaultValue : Integer.parseInt(stringValue); }catch(NumberFormatException e){ return defaultValue; } } @Override public String toString(){ return "SM="+_spaceMonitorHandler+";S="+_status; } @Override public void runIO(FileAttributes fileAttributes, RepositoryChannel fileChannel, ProtocolInfo protocol, Allocator allocator, IoMode access ) throws Exception { configureBufferSizes(); Exception ioException = null; if(! (protocol instanceof DCapProtocolInfo)) { throw new CacheException(44, "protocol info not DCapProtocolInfo"); } DCapProtocolInfo dcapProtocolInfo = (DCapProtocolInfo)protocol; StorageInfo storage = fileAttributes.getStorageInfo(); _pnfsId = fileAttributes.getPnfsId(); _spaceMonitorHandler = new SpaceMonitorHandler(allocator); //////////////////////////////////////////////////////////////////////// // // // Prepare the tunable parameters // // // try{ String allocation = storage.getKey("alloc-size"); if(allocation != null){ long allocSpace = Long.parseLong(allocation); if(allocSpace <= 0) { // negative allocation requested....Ignoring _log.info("Options : alloc-space = {} ....Ignoring", allocSpace); }else{ _spaceMonitorHandler.setAllocationSpace(allocSpace); _log.info("Options : alloc-space = {}", allocSpace); } } }catch(NumberFormatException e){ /* bad values are ignored */} try{ String io = storage.getKey("io-error"); if(io != null) { _ioError = Long.parseLong(io); } }catch(NumberFormatException e){ /* bad values are ignored */} _log.info("ioError = {}", _ioError); // gets the buffervalues of the storageInfo keys MoverIoBuffer bufferSize = prepareBufferSize(storage); _log.info("Client : Buffer Sizes : {}", bufferSize); // allocates the _bigBuffer initialiseBuffer(bufferSize); SocketChannel socketChannel = null; DCapOutputByteBuffer cntOut = new DCapOutputByteBuffer(KiB.toBytes(1)); _sessionId = dcapProtocolInfo.getSessionId(); if(! dcapProtocolInfo.isPassive()) { socketChannel = SocketChannel.open(); socketChannel.configureBlocking(true); Socket socket = socketChannel.socket(); socket.setKeepAlive(true); socket.setTcpNoDelay(true); if (bufferSize.getRecvBufferSize() > 0) { socket.setReceiveBufferSize(bufferSize .getRecvBufferSize()); } if (bufferSize.getSendBufferSize() > 0) { socket.setSendBufferSize(bufferSize .getSendBufferSize()); } socketChannel.connect(dcapProtocolInfo.getSocketAddress()); if (_logSocketIO.isDebugEnabled()) { _logSocketIO.debug("Socket OPEN remote = {}:{} local = {}:{}", socket.getInetAddress(), socket.getPort(), socket.getLocalAddress(), socket.getLocalPort()); } _log.info("Using : Buffer Sizes (send/recv/io) : {}/{}/{}", socket.getSendBufferSize(), socket.getReceiveBufferSize(), _bigBuffer.capacity()); _log.info("Connected to {}", dcapProtocolInfo.getSocketAddress()); // // send the sessionId and our (for now) 0 byte security challenge. // _bigBuffer.clear(); _bigBuffer.putInt(_sessionId).putInt(0); _bigBuffer.flip(); socketChannel.write(_bigBuffer); }else{ // passive connection try (Listen listen = factory.acquireListen(bufferSize.getRecvBufferSize())) { InetAddress localAddress = NetworkUtils. getLocalAddress(dcapProtocolInfo.getSocketAddress().getAddress()); InetSocketAddress socketAddress = new InetSocketAddress(localAddress, listen.getPort()); byte[] challenge = UUID.randomUUID().toString().getBytes(); PoolPassiveIoFileMessage<byte[]> msg = new PoolPassiveIoFileMessage<>("pool", socketAddress, challenge); msg.setId(dcapProtocolInfo.getSessionId()); _log.info("waiting for client to connect ({}:{})", localAddress, listen.getPort()); CellPath cellpath = dcapProtocolInfo.door(); _cell.sendMessage (new CellMessage(cellpath, msg)); DCapProrocolChallenge dcapChallenge = new DCapProrocolChallenge(_sessionId, challenge); socketChannel = listen.getSocket(dcapChallenge); } Socket socket = socketChannel.socket(); socket.setKeepAlive(true); socket.setTcpNoDelay(true); if (bufferSize.getSendBufferSize() > 0) { socket.setSendBufferSize(bufferSize.getSendBufferSize()); } } // // _transferStarted = System.currentTimeMillis(); _bytesTransferred = 0; _lastTransferred = _transferStarted; _spaceMonitorHandler.setInitialSpace(fileChannel.size()); boolean notDone = true; RequestBlock requestBlock = new RequestBlock(); try{ while(notDone && _io_ok){ if(Thread.interrupted()) { throw new InterruptedException("Interrupted By Operator"); } // // read and process DCAP request // try { requestBlock.read(socketChannel); } catch (CacheException e) { // CacheException thrown only on protocol violation. cntOut.writeACK(9, e.getRc(), e.getMessage()); socketChannel.write(cntOut.buffer()); continue; } _log.debug("Request Block : {}", requestBlock); _lastTransferred = System.currentTimeMillis(); switch(requestBlock.getCommandCode()){ //------------------------------------------------------------- // // The Write // case DCapConstants.IOCMD_WRITE : // // no further arguments (yet) // if(! _io_ok){ String errmsg = "WRITE denied (IO not ok)"; _log.error(errmsg); cntOut.writeACK(DCapConstants.IOCMD_WRITE,CacheException.ERROR_IO_DISK,errmsg); socketChannel.write(cntOut.buffer()); }else if(access == IoMode.WRITE){ // // The 'REQUEST ACK' // cntOut.writeACK(DCapConstants.IOCMD_WRITE); socketChannel.write(cntOut.buffer()); // doTheWrite(fileChannel, cntOut, socketChannel); // // if(_io_ok){ cntOut.writeFIN(DCapConstants.IOCMD_WRITE); socketChannel.write(cntOut.buffer()); }else{ _log.error("Reporting IO problem to client"); cntOut.writeFIN(DCapConstants.IOCMD_WRITE,CacheException.ERROR_IO_DISK, "[2]Problem in writing"); socketChannel.write(cntOut.buffer()); } }else{ String errmsg = "WRITE denied (not allowed)"; _log.error(errmsg); cntOut.writeACK(DCapConstants.IOCMD_WRITE,CacheException.ERROR_IO_DISK,errmsg); socketChannel.write(cntOut.buffer()); } break; //------------------------------------------------------------- // // The Read // case DCapConstants.IOCMD_READ : // // _digest = null; long blockSize = requestBlock.nextLong(); _log.debug("READ byte={}", blockSize); if(_io_ok){ cntOut.writeACK(DCapConstants.IOCMD_READ); socketChannel.write(cntOut.buffer()); doTheRead(fileChannel, cntOut, socketChannel, blockSize); if(_io_ok){ cntOut.writeFIN(DCapConstants.IOCMD_READ); socketChannel.write(cntOut.buffer()); }else{ String errmsg = "FIN : READ failed (IO not ok)"; _log.error(errmsg); cntOut.writeFIN(DCapConstants.IOCMD_READ,CacheException.ERROR_IO_DISK,errmsg); socketChannel.write(cntOut.buffer()); } }else{ String errmsg = "ACK : READ denied (IO not ok)"; _log.error(errmsg); cntOut.writeACK(DCapConstants.IOCMD_READ,CacheException.ERROR_IO_DISK,errmsg); socketChannel.write(cntOut.buffer()); } break; //------------------------------------------------------------- // // The Seek // case DCapConstants.IOCMD_SEEK : _digest = null; long offset = requestBlock.nextLong(); int whence = requestBlock.nextInt(); doTheSeek(fileChannel , whence, offset, (access == IoMode.WRITE) ); if(_io_ok){ cntOut.writeACK(fileChannel.position()); socketChannel.write(cntOut.buffer()); }else{ String errmsg = "SEEK failed : IOError "; _log.error(errmsg); cntOut.writeACK(DCapConstants.IOCMD_SEEK,6,errmsg); socketChannel.write(cntOut.buffer()); } break; //------------------------------------------------------------- // // The IOCMD_SEEK_AND_READ // case DCapConstants.IOCMD_SEEK_AND_READ : _digest = null; offset = requestBlock.nextLong(); whence = requestBlock.nextInt(); blockSize = requestBlock.nextLong(); if(_io_ok){ cntOut.writeACK(DCapConstants.IOCMD_SEEK_AND_READ); socketChannel.write(cntOut.buffer()); doTheSeek(fileChannel, whence, offset, (access == IoMode.WRITE) ); if(_io_ok) { doTheRead(fileChannel, cntOut, socketChannel, blockSize); } if(_io_ok){ cntOut.writeFIN(DCapConstants.IOCMD_SEEK_AND_READ); socketChannel.write(cntOut.buffer()); }else{ String errmsg = "FIN : SEEK_READ failed (IO not ok)"; _log.error(errmsg); cntOut.writeFIN(DCapConstants.IOCMD_SEEK_AND_READ,CacheException.ERROR_IO_DISK,errmsg); socketChannel.write(cntOut.buffer()); } }else{ String errmsg = "SEEK_AND_READ denied : IOError " ; _log.error(errmsg); cntOut.writeACK(DCapConstants.IOCMD_SEEK_AND_READ,CacheException.ERROR_IO_DISK,errmsg); socketChannel.write(cntOut.buffer()); } break; //------------------------------------------------------------- // // The IOCMD_SEEK_AND_WRITE // case DCapConstants.IOCMD_SEEK_AND_WRITE : _digest = null; offset = requestBlock.nextLong(); whence = requestBlock.nextInt(); if(!_io_ok) { String errmsg = "SEEK_AND_WRITE denied : IOError"; _log.error(errmsg); cntOut.writeACK(DCapConstants.IOCMD_SEEK_AND_WRITE, CacheException.ERROR_IO_DISK, errmsg); socketChannel.write(cntOut.buffer()); } else if (access != IoMode.WRITE) { String errmsg = "SEEK_AND_WRITE denied (not allowed)"; _log.error(errmsg); cntOut.writeACK(DCapConstants.IOCMD_SEEK_AND_WRITE, CacheException.ERROR_IO_DISK, errmsg); socketChannel.write(cntOut.buffer()); } else { cntOut.writeACK(DCapConstants.IOCMD_SEEK_AND_WRITE); socketChannel.write(cntOut.buffer()); doTheSeek(fileChannel, whence, offset, (access == IoMode.WRITE) ); if(_io_ok) { doTheWrite(fileChannel, cntOut, socketChannel); } if(_io_ok){ cntOut.writeFIN(DCapConstants.IOCMD_SEEK_AND_WRITE); socketChannel.write(cntOut.buffer()); }else{ String errmsg = "SEEK_AND_WRITE failed : IOError"; _log.error(errmsg); cntOut.writeFIN(DCapConstants.IOCMD_SEEK_AND_WRITE,CacheException.ERROR_IO_DISK,errmsg); socketChannel.write(cntOut.buffer()); } } break; //------------------------------------------------------------- // // The IOCMD_CLOSE // case DCapConstants.IOCMD_CLOSE : if(_io_ok){ cntOut.writeACK(DCapConstants.IOCMD_CLOSE); socketChannel.write(cntOut.buffer()); try{ while(requestBlock.remaining() > 4){ scanCloseBlock(requestBlock,storage); } }catch(Exception ee){ _log.error("Problem in close block {}", ee.toString()); } }else{ cntOut.writeACK(DCapConstants.IOCMD_CLOSE,CacheException.ERROR_IO_DISK,"IOError"); socketChannel.write(cntOut.buffer()); } notDone = false; break; //------------------------------------------------------------- // // The IOCMD_LOCATE // case DCapConstants.IOCMD_LOCATE : try{ long size = fileChannel.position(); long location = fileChannel.size(); _log.debug("LOCATE : size={};position={}", size, location); cntOut.writeACK(location, size); socketChannel.write(cntOut.buffer()); }catch(Exception e){ cntOut.writeACK(DCapConstants.IOCMD_LOCATE,-1,e.toString()); socketChannel.write(cntOut.buffer()); } break; //------------------------------------------------------------- // // The IOCMD_READV (vector read) // case DCapConstants.IOCMD_READV : try{ if(_io_ok){ cntOut.writeACK(DCapConstants.IOCMD_READV); socketChannel.write(cntOut.buffer()); doTheReadv(fileChannel, cntOut, socketChannel, requestBlock); if(_io_ok){ cntOut.writeFIN(DCapConstants.IOCMD_READV); socketChannel.write(cntOut.buffer()); }else{ String errmsg = "FIN : READV failed (IO not ok)"; _log.error(errmsg); cntOut.writeFIN(DCapConstants.IOCMD_READV,CacheException.ERROR_IO_DISK,errmsg); socketChannel.write(cntOut.buffer()); } }else{ String errmsg = "ACK : READV denied (IO not ok)"; _log.error(errmsg); cntOut.writeACK(DCapConstants.IOCMD_READV,CacheException.ERROR_IO_DISK,errmsg); socketChannel.write(cntOut.buffer()); } }catch(Exception e){ cntOut.writeACK(DCapConstants.IOCMD_READV,-1,e.toString()); socketChannel.write(cntOut.buffer()); } break; default : cntOut.writeACK(666, 9,"Invalid mover command : "+requestBlock); socketChannel.write(cntOut.buffer()); } } }catch(RuntimeException e){ _log.error("Problem in command block : "+requestBlock, e); ioException = e; } catch (ClosedByInterruptException ee) { // clear interrupted state Thread.interrupted(); ioException = new InterruptedException(ee.getMessage()); } catch (EOFException e) { _log.debug("Dataconnection closed by peer : {}", e.toString()); ioException = e; }catch(Exception e){ ioException = e; }finally{ try{ _logSocketIO.debug("Socket CLOSE remote = {}:{} local {}:{}", socketChannel.socket().getInetAddress(), socketChannel.socket().getPort(), socketChannel.socket().getLocalAddress(), socketChannel.socket().getLocalPort()); socketChannel.close(); }catch(Exception xe){} dcapProtocolInfo.setBytesTransferred(_bytesTransferred); _transferTime = System.currentTimeMillis() - _transferStarted; dcapProtocolInfo.setTransferTime(_transferTime); _log.info("(Transfer finished : {} bytes in {} seconds) ", _bytesTransferred, _transferTime/1000); // // if we got an EOF from the inputstream // we cancel the request but we don't want to // disable the pool, unless client is gone while // got an IO error report from pool. // if(! _io_ok) { throw new DiskErrorCacheException( "Disk I/O Error " + (ioException!=null?ioException.toString():"")); }else{ if (ioException != null && !(ioException instanceof EOFException)) { _log.warn("Problem in command block : {} {}", requestBlock, ioException.toString()); throw ioException; } } } } private void doTheReadv(RepositoryChannel fileChannel, DCapOutputByteBuffer cntOut, SocketChannel socketChannel, RequestBlock requestBLock) throws Exception { cntOut.writeDATA_HEADER(); socketChannel.write(cntOut.buffer()); int blocks = requestBLock.nextInt(); _log.debug("READV: {} to read", blocks); final int maxBuffer = _bigBuffer.capacity() - 4; for(int i = 0; i < blocks; i++) { long offset = requestBLock.nextLong(); int count = requestBLock.nextInt(); int len = count; _log.debug("READV: offset/len: {}/{}", offset, count); while(count > 0) { int bytesToRead = maxBuffer > count ? count : maxBuffer; int rc; try{ _bigBuffer.clear().limit(bytesToRead+4); _bigBuffer.position(4); rc = fileChannel.read(_bigBuffer, offset + (len - count)); if(rc <= 0) { break; } }catch (ClosedByInterruptException ee) { // clear interrupted state Thread.interrupted(); throw new InterruptedException(ee.getMessage()); }catch(IOException ee){ _io_ok = false; break; } _bigBuffer.flip(); _bigBuffer.putInt(rc).rewind(); _log.debug("READV: sending: {} bytes", _bigBuffer.limit()); socketChannel.write(_bigBuffer); count -= rc; _bytesTransferred += rc; } } } private void scanCloseBlock(RequestBlock requestBlock, StorageInfo storage) { // // Close Block Format : // Size Purpose // 4 (Size following) // 4 sub block type (1=crc) // // if crc // 4 crc type (1=adler32) // n checksum // int blockSize = requestBlock.nextInt(); if(blockSize < 4){ _log.error("Not a valid block size in close"); throw new IllegalArgumentException("Not a valid block size in close"); } int blockMode = requestBlock.nextInt(); if(blockMode != 1){ // crc block _log.error("Unknown block mode ({}) in close", blockMode); requestBlock.skip(blockSize-4); return ; } int crcType = requestBlock.nextInt(); byte [] array = new byte[blockSize-8]; requestBlock.get(array); _clientChecksum = new Checksum(ChecksumType.getChecksumType(crcType), array); storage.setKey("flag-c",_clientChecksum.toString()); } private void doTheSeek(RepositoryChannel fileChannel, int whence, long offset, boolean writeAllowed) { try{ long eofSize = fileChannel.size(); long position = fileChannel.position(); long newOffset; switch(whence){ case DCapConstants.IOCMD_SEEK_SET : _log.debug("SEEK {} SEEK_SET", offset); // // this should reset the io state // if(offset == 0L) { _io_ok = true; } // newOffset = offset; break; case DCapConstants.IOCMD_SEEK_CURRENT : _log.debug("SEEK {} SEEK_CURRENT", offset); newOffset = position + offset; break; case DCapConstants.IOCMD_SEEK_END : _log.debug("SEEK {} SEEK_END", offset); newOffset = eofSize + offset; break; default : throw new IllegalArgumentException("Invalid seek mode : "+whence); } if((newOffset > eofSize) && ! writeAllowed) { throw new IOException("Seek beyond EOF not allowed (write not allowed)"); } // // allocate the space if necessary // _spaceMonitorHandler.getSpace(newOffset); // // set the new file offset // fileChannel.position(newOffset); // // // Because the seek beyond the EOF doesn't change // the eof, must not call newFilePosition. // // _spaceMonitorHandler.newFilePosition(newOffset); // }catch(Exception ee){ // // don't disable pools because of this. // // _io_ok = false; _log.error("Problem in seek : {}", ee.toString()); } } private void doTheWrite(RepositoryChannel fileChannel, DCapOutputByteBuffer cntOut, SocketChannel socketChannel ) throws Exception{ int rest; int size, rc; RequestBlock requestBlock = new RequestBlock(); requestBlock.read(socketChannel); if(requestBlock.getCommandCode() != DCapConstants.IOCMD_DATA) { throw new IOException("Expecting : " + DCapConstants.IOCMD_DATA + "; got : " + requestBlock .getCommandCode()); } while(! Thread.currentThread().isInterrupted()){ _status = "WaitingForSize"; _bigBuffer.clear().limit(4); while(_bigBuffer.hasRemaining()){ if(socketChannel.read(_bigBuffer) < 0) { throw new EOFException("EOF on input socket"); } } _bigBuffer.rewind(); rest = _bigBuffer.getInt(); _log.debug("Next data block : {} bytes", rest); // // if there is a space monitor, we use it // long position = fileChannel.position(); // // allocate the space // _spaceMonitorHandler.getSpace(position + rest); // // we take whatever we get from the client // and at the end we tell'em that something went // terribly wrong. // long bytesAdded = 0L; if(rest == 0) { continue; } if(rest < 0) { break; } while(rest > 0 ){ size = _bigBuffer.capacity() > rest ? rest : _bigBuffer.capacity(); _status = "WaitingForInput"; _bigBuffer.clear().limit(size); rc = socketChannel.read(_bigBuffer); if(rc <= 0) { break; } if(_io_ok){ _status = "WaitingForWrite"; try{ _bigBuffer.flip(); bytesAdded += fileChannel.write(_bigBuffer); updateChecksum(_bigBuffer); } catch (ClosedByInterruptException ee) { // clear interrupted state Thread.interrupted(); throw new InterruptedException(ee.getMessage()); }catch(IOException ioe){ _log.error("IOException in writing data to disk : {}", ioe.toString()); _io_ok = false; } } rest -= rc; _bytesTransferred += rc; if((_ioError > 0L) && (_bytesTransferred > _ioError)){ _io_ok = false; } } _spaceMonitorHandler.newFilePosition(position + bytesAdded); _log.debug("Block Done"); } _status = "Done"; } private void updateChecksum(ByteBuffer buffer){ if (_digest != null) { buffer.rewind(); _digest.update(buffer); } } private void doTheRead(RepositoryChannel fileChannel, DCapOutputByteBuffer cntOut, SocketChannel socketChannel, long blockSize) throws Exception{ // // REQUEST WRITE // cntOut.writeDATA_HEADER(); socketChannel.write(cntOut.buffer()); // // if(blockSize == 0){ cntOut.writeEND_OF_BLOCK(); socketChannel.write(cntOut.buffer()); return; } long rest = blockSize; int size, rc; final int maxBuffer = _bigBuffer.capacity() - 4; while(! Thread.currentThread().isInterrupted()){ size = maxBuffer > rest ? (int)rest : maxBuffer; try{ _bigBuffer.clear().limit(size+4); _bigBuffer.position(4); rc = fileChannel.read(_bigBuffer); if(rc <= 0) { break; } } catch (ClosedByInterruptException ee) { // clear interrupted state Thread.interrupted(); throw new InterruptedException(ee.getMessage()); }catch(IOException ee){ _io_ok = false; break; } _bigBuffer.flip(); _bigBuffer.putInt(rc).rewind(); socketChannel.write(_bigBuffer); rest -= rc; _bytesTransferred += rc; if((_ioError > 0L) && (_bytesTransferred > _ioError)){ _io_ok = false; break; } if(rest <= 0) { break; } } // // data chain delimiter // cntOut.writeDATA_TRAILER(); socketChannel.write(cntOut.buffer()); } @Override public long getLastTransferred() { return _lastTransferred; } @Override public long getBytesTransferred(){ return _bytesTransferred ; } @Override public long getTransferTime(){ return _transferTime < 0 ? System.currentTimeMillis() - _transferStarted : _transferTime ; } @Override public void enableTransferChecksum(ChecksumType suggestedAlgorithm) throws NoSuchAlgorithmException { _checksumFactory = ChecksumFactory.getFactory(suggestedAlgorithm); _digest = _checksumFactory.create(); } @Override public Checksum getExpectedChecksum(){ return _clientChecksum ; } @Override public Checksum getActualChecksum(){ return (_digest == null) ? null : _checksumFactory.create(_digest.digest()); } }