001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020 021package org.apache.mina.filter.ssl; 022 023import static org.junit.Assert.assertEquals; 024 025import java.util.ArrayList; 026import java.util.List; 027import java.util.concurrent.ExecutorService; 028import java.util.concurrent.Executors; 029import java.util.concurrent.Future; 030 031import javax.net.ssl.SSLException; 032 033import org.apache.mina.core.filterchain.IoFilter.NextFilter; 034import org.apache.mina.core.session.DummySession; 035import org.apache.mina.core.session.IdleStatus; 036import org.apache.mina.core.session.IoSession; 037import org.apache.mina.core.write.DefaultWriteRequest; 038import org.apache.mina.core.write.WriteRequest; 039import org.junit.Before; 040import org.junit.Test; 041 042/** 043 * A test for DIRMINA-1019 044 * @author <a href="http://mina.apache.org">Apache MINA Project</a> 045 */ 046abstract class AbstractNextFilter implements NextFilter { 047 public abstract void messageReceived(IoSession session, Object message); 048 049 public abstract void filterWrite(IoSession session, WriteRequest writeRequest); 050 051 // Following are unimplemented as they aren't used in test 052 public void sessionCreated(IoSession session) { } 053 054 public void sessionOpened(IoSession session) { } 055 056 public void sessionClosed(IoSession session) { } 057 058 public void sessionIdle(IoSession session, IdleStatus status) { } 059 060 public void exceptionCaught(IoSession session, Throwable cause) { } 061 062 public void inputClosed(IoSession session) { } 063 064 public void messageSent(IoSession session, WriteRequest writeRequest) { } 065 066 public void filterClose(IoSession session) { } 067 068 public String toString() { 069 return null; 070 } 071}; 072 073/** 074 * A test for DIRMINA-1019 075 * @author <a href="http://mina.apache.org">Apache MINA Project</a> 076 */ 077public class SslFilterTest { 078 SslHandler test_class; 079 080 @Before 081 public void init() throws SSLException { 082 test_class = new SslHandler(null, new DummySession()); 083 } 084 085 @Test 086 public void testFlushRaceCondition() { 087 final ExecutorService executor = Executors.newFixedThreadPool(1); 088 final List<Object> message_received_messages = new ArrayList<Object>(); 089 final List<WriteRequest> filter_write_requests = new ArrayList<WriteRequest>(); 090 091 final AbstractNextFilter write_filter = new AbstractNextFilter() 092 { 093 @Override 094 public void messageReceived(IoSession session, Object message) { } 095 096 @Override 097 public void filterWrite(IoSession session, WriteRequest writeRequest) { 098 filter_write_requests.add(writeRequest); 099 } 100 }; 101 102 AbstractNextFilter receive_filter = new AbstractNextFilter() 103 { 104 @Override 105 public void messageReceived(IoSession session, Object message) { 106 message_received_messages.add(message); 107 108 // This is where the race condition occurs. If a thread calls SslHandler.scheduleFilterWrite(), 109 // followed by SslHandler.flushScheduledEvents(), the queued event will not be processed as 110 // the current thread owns the SslHandler.sslLock and has already "dequeued" all the queued 111 // filterWriteEventQueue. 112 Future<?> write_scheduler = executor.submit(new Runnable() { 113 public void run() { 114 test_class.scheduleFilterWrite(write_filter, new DefaultWriteRequest(new byte[] {})); 115 test_class.flushScheduledEvents(); 116 } 117 }); 118 119 try { 120 write_scheduler.get(); 121 } catch (Exception e) { } 122 } 123 124 @Override 125 public void filterWrite(IoSession session, WriteRequest writeRequest) { } 126 }; 127 128 test_class.scheduleMessageReceived(receive_filter, new byte[] {}); 129 test_class.flushScheduledEvents(); 130 131 assertEquals(1, message_received_messages.size()); 132 assertEquals(1, filter_write_requests.size()); 133 } 134}