public boolean matches(Object actual) { if (actual instanceof WriteRequest) { WriteRequest w2 = (WriteRequest) actual; return expected.getMessage().equals(w2.getMessage()) && expected.getFuture().isWritten() == w2.getFuture().isWritten(); } return false; }
@Test public void testWriteEmptyFile() throws Exception { AbstractStreamWriteFilter<M> filter = createFilter(); M message = createMessage(new byte[0]); WriteRequest writeRequest = new DefaultWriteRequest(message, new DummyWriteFuture()); NextFilter nextFilter = EasyMock.createMock(NextFilter.class); /* * Record expectations */ nextFilter.messageSent(session, writeRequest); /* * Replay. */ EasyMock.replay(nextFilter); filter.filterWrite(nextFilter, session, writeRequest); /* * Verify. */ EasyMock.verify(nextFilter); assertTrue(writeRequest.getFuture().isWritten()); }
/** * Tests when the contents of the file fits into one write buffer. * * @throws Exception when something goes wrong */ @Test public void testWriteSingleBufferFile() throws Exception { byte[] data = new byte[] {1, 2, 3, 4}; AbstractStreamWriteFilter<M> filter = createFilter(); M message = createMessage(data); WriteRequest writeRequest = new DefaultWriteRequest(message, new DummyWriteFuture()); NextFilter nextFilter = EasyMock.createMock(NextFilter.class); /* * Record expectations */ nextFilter.filterWrite( EasyMock.eq(session), eqWriteRequest(new DefaultWriteRequest(IoBuffer.wrap(data)))); nextFilter.messageSent(session, writeRequest); /* * Replay. */ EasyMock.replay(nextFilter); filter.filterWrite(nextFilter, session, writeRequest); filter.messageSent(nextFilter, session, writeRequest); /* * Verify. */ EasyMock.verify(nextFilter); assertTrue(writeRequest.getFuture().isWritten()); }
public void wrap(NextFilter nextFilter, WriteRequest writeRequest, IoBuffer buf) throws AuthException { int start = buf.position(); int len = buf.remaining() - LINE_TERMINATOR.length; if (len == 0) throw new AuthException("Decryption failed"); // HMAC(Ki, {SeqNum, msg})[0..9] byte[] originalMessage = new byte[len]; buf.get(originalMessage); byte[] mac = AuthDigestMD5IoFilter.computeMACBlock(session, originalMessage, false); // Calculate padding int bs = encCipher.getBlockSize(); byte[] padding; if (bs > 1) { int pad = bs - ((len + 10) % bs); // add 10 for HMAC[0..9] padding = new byte[pad]; for (int i = 0; i < pad; i++) padding[i] = (byte) pad; } else padding = EMPTY_BYTE_ARRAY; byte[] toBeEncrypted = new byte[len + padding.length + 10]; // {msg, pad, HMAC(Ki, {SeqNum, msg}[0..9])} System.arraycopy(originalMessage, start, toBeEncrypted, 0, len); System.arraycopy(padding, 0, toBeEncrypted, len, padding.length); System.arraycopy(mac, 0, toBeEncrypted, len + padding.length, 10); // CIPHER(Kc, {msg, pad, HMAC(Ki, {SeqNum, msg}[0..9])}) byte[] cipherBlock; try { // Do CBC (chaining) across packets cipherBlock = encCipher.update(toBeEncrypted); // update() can return null if (cipherBlock == null) throw new IllegalBlockSizeException("" + toBeEncrypted.length); } catch (IllegalBlockSizeException e) { throw new AuthException("Invalid block size for cipher", e); } IoBuffer out = IoBuffer.allocate(cipherBlock.length + 2 + 4 + LINE_TERMINATOR.length); out.put(cipherBlock); out.put(mac, 10, 6); // messageType & sequenceNum out.put(LINE_TERMINATOR); out.flip(); if (out.limit() > ((Integer) session.getAttribute(AuthDigestMD5Command.CLIENT_MAXBUF)).intValue()) throw new AuthException("Data exceeds client maxbuf capability"); nextFilter.filterWrite(session, new DefaultWriteRequest(out, writeRequest.getFuture())); }
private void clearWriteRequestQueue(S session) { WriteRequestQueue writeRequestQueue = session.getWriteRequestQueue(); WriteRequest req; List<WriteRequest> failedRequests = new ArrayList<WriteRequest>(); if ((req = writeRequestQueue.poll(session)) != null) { Object message = req.getMessage(); if (message instanceof IoBuffer) { IoBuffer buf = (IoBuffer) message; // The first unwritten empty buffer must be // forwarded to the filter chain. if (buf.hasRemaining()) { buf.reset(); failedRequests.add(req); } else { IoFilterChain filterChain = session.getFilterChain(); filterChain.fireMessageSent(req); } } else { failedRequests.add(req); } // Discard others. while ((req = writeRequestQueue.poll(session)) != null) { failedRequests.add(req); } } // Create an exception and notify. if (!failedRequests.isEmpty()) { WriteToClosedSessionException cause = new WriteToClosedSessionException(failedRequests); for (WriteRequest r : failedRequests) { session.decreaseScheduledBytesAndMessages(r); r.getFuture().setException(cause); } IoFilterChain filterChain = session.getFilterChain(); filterChain.fireExceptionCaught(cause); } }
/** * Tests when the contents of the file doesn't fit into one write buffer. * * @throws Exception when something goes wrong */ @Test public void testWriteSeveralBuffersStream() throws Exception { AbstractStreamWriteFilter<M> filter = createFilter(); filter.setWriteBufferSize(4); byte[] data = new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; byte[] chunk1 = new byte[] {1, 2, 3, 4}; byte[] chunk2 = new byte[] {5, 6, 7, 8}; byte[] chunk3 = new byte[] {9, 10}; M message = createMessage(data); WriteRequest writeRequest = new DefaultWriteRequest(message, new DummyWriteFuture()); WriteRequest chunk1Request = new DefaultWriteRequest(IoBuffer.wrap(chunk1)); WriteRequest chunk2Request = new DefaultWriteRequest(IoBuffer.wrap(chunk2)); WriteRequest chunk3Request = new DefaultWriteRequest(IoBuffer.wrap(chunk3)); NextFilter nextFilter = EasyMock.createMock(NextFilter.class); /* * Record expectations */ nextFilter.filterWrite(EasyMock.eq(session), eqWriteRequest(chunk1Request)); nextFilter.filterWrite(EasyMock.eq(session), eqWriteRequest(chunk2Request)); nextFilter.filterWrite(EasyMock.eq(session), eqWriteRequest(chunk3Request)); nextFilter.messageSent(EasyMock.eq(session), eqWriteRequest(writeRequest)); /* * Replay. */ EasyMock.replay(nextFilter); filter.filterWrite(nextFilter, session, writeRequest); filter.messageSent(nextFilter, session, chunk1Request); filter.messageSent(nextFilter, session, chunk2Request); filter.messageSent(nextFilter, session, chunk3Request); /* * Verify. */ EasyMock.verify(nextFilter); assertTrue(writeRequest.getFuture().isWritten()); }
private boolean flushNow(S session, long currentTime) { if (!session.isConnected()) { scheduleRemove(session); return false; } final boolean hasFragmentation = session.getTransportMetadata().hasFragmentation(); final WriteRequestQueue writeRequestQueue = session.getWriteRequestQueue(); // Set limitation for the number of written bytes for read-write // fairness. I used maxReadBufferSize * 3 / 2, which yields best // performance in my experience while not breaking fairness much. final int maxWrittenBytes = session.getConfig().getMaxReadBufferSize() + (session.getConfig().getMaxReadBufferSize() >>> 1); int writtenBytes = 0; WriteRequest req = null; try { // Clear OP_WRITE setInterestedInWrite(session, false); do { // Check for pending writes. req = session.getCurrentWriteRequest(); if (req == null) { req = writeRequestQueue.poll(session); if (req == null) { break; } session.setCurrentWriteRequest(req); } int localWrittenBytes = 0; Object message = req.getMessage(); if (message instanceof IoBuffer) { localWrittenBytes = writeBuffer( session, req, hasFragmentation, maxWrittenBytes - writtenBytes, currentTime); if ((localWrittenBytes > 0) && ((IoBuffer) message).hasRemaining()) { // the buffer isn't empty, we re-interest it in writing writtenBytes += localWrittenBytes; setInterestedInWrite(session, true); return false; } } else if (message instanceof FileRegion) { localWrittenBytes = writeFile( session, req, hasFragmentation, maxWrittenBytes - writtenBytes, currentTime); // Fix for Java bug on Linux // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5103988 // If there's still data to be written in the FileRegion, // return 0 indicating that we need // to pause until writing may resume. if ((localWrittenBytes > 0) && (((FileRegion) message).getRemainingBytes() > 0)) { writtenBytes += localWrittenBytes; setInterestedInWrite(session, true); return false; } } else { throw new IllegalStateException( "Don't know how to handle message of type '" + message.getClass().getName() + "'. Are you missing a protocol encoder?"); } if (localWrittenBytes == 0) { // Kernel buffer is full. setInterestedInWrite(session, true); return false; } writtenBytes += localWrittenBytes; if (writtenBytes >= maxWrittenBytes) { // Wrote too much scheduleFlush(session); return false; } } while (writtenBytes < maxWrittenBytes); } catch (Exception e) { if (req != null) { req.getFuture().setException(e); } IoFilterChain filterChain = session.getFilterChain(); filterChain.fireExceptionCaught(e); return false; } return true; }