private boolean flush(DatagramSessionImpl session) throws IOException {
        // Clear OP_WRITE
        SelectionKey key = session.getSelectionKey();
        if (key == null) {
            scheduleFlush(session);
            return false;
        }
        if (!key.isValid()) {
            return false;
        }
        key.interestOps(key.interestOps() & (~SelectionKey.OP_WRITE));

        DatagramChannel ch = session.getChannel();
        Queue<WriteRequest> writeRequestQueue = session.getWriteRequestQueue();

        int writtenBytes = 0;
        int maxWrittenBytes = ((DatagramSessionConfig) session.getConfig()).getSendBufferSize() << 1;
        try {
            for (;;) {
                WriteRequest req = writeRequestQueue.peek();
        
                if (req == null)
                    break;
        
                ByteBuffer buf = (ByteBuffer) req.getMessage();
                if (buf.remaining() == 0) {
                    // pop and fire event
                    writeRequestQueue.poll();
        
                    buf.reset();
                    
                    if (!buf.hasRemaining()) {
                        session.increaseWrittenMessages();
                    }

                    session.getFilterChain().fireMessageSent(session, req);
                    continue;
                }
        
                int localWrittenBytes = ch.write(buf.buf());
                writtenBytes += localWrittenBytes;
    
                if (localWrittenBytes == 0 || writtenBytes >= maxWrittenBytes) {
                    // Kernel buffer is full or wrote too much
                    key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
                    return false;
                } else {
                    key.interestOps(key.interestOps() & (~SelectionKey.OP_WRITE));
    
                    // pop and fire event
                    writeRequestQueue.poll();
    
                    buf.reset();
                    
                    if (!buf.hasRemaining()) {
                        session.increaseWrittenMessages();
                    }
                    
                    session.getFilterChain().fireMessageSent(session, req);
                }
            }
        } finally {
            session.increaseWrittenBytes(writtenBytes);
        }
        
        return true;
    }