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 */ 020package org.apache.mina.example.echoserver; 021import static org.junit.Assert.assertEquals; 022 023import java.io.IOException; 024import java.net.InetSocketAddress; 025import java.net.SocketAddress; 026import java.security.GeneralSecurityException; 027 028import org.apache.mina.core.buffer.IoBuffer; 029import org.apache.mina.core.service.IoAcceptor; 030import org.apache.mina.core.session.IoSession; 031import org.apache.mina.example.echoserver.ssl.BogusSslContextFactory; 032import org.apache.mina.filter.ssl.SslFilter; 033import org.apache.mina.transport.socket.DatagramSessionConfig; 034import org.apache.mina.transport.socket.nio.NioDatagramAcceptor; 035import org.apache.mina.transport.socket.nio.NioSocketAcceptor; 036import org.apache.mina.util.AvailablePortFinder; 037import org.junit.After; 038import org.junit.Before; 039import org.slf4j.Logger; 040import org.slf4j.LoggerFactory; 041 042/** 043 * Tests echo server example. 044 * 045 * @author <a href="http://mina.apache.org">Apache MINA Project</a> 046 */ 047public abstract class AbstractTest { 048 private final static Logger LOGGER = LoggerFactory.getLogger(AbstractTest.class); 049 050 protected boolean useSSL; 051 052 protected int port; 053 054 protected SocketAddress boundAddress; 055 056 protected IoAcceptor datagramAcceptor; 057 058 protected IoAcceptor socketAcceptor; 059 060 protected AbstractTest() { 061 // Do nothing 062 } 063 064 protected static void isEquals(byte[] expected, byte[] actual) { 065 assertEquals(toString(expected), toString(actual)); 066 } 067 068 protected static void isEquals(IoBuffer expected, IoBuffer actual) { 069 assertEquals(toString(expected), toString(actual)); 070 } 071 072 protected static String toString(byte[] buf) { 073 StringBuilder str = new StringBuilder(buf.length * 4); 074 for (byte element : buf) { 075 str.append(element); 076 str.append(' '); 077 } 078 return str.toString(); 079 } 080 081 protected static String toString(IoBuffer buf) { 082 return buf.getHexDump(); 083 } 084 085 @Before 086 public void setUp() throws Exception { 087 // Disable SSL by default 088 useSSL = false; 089 090 boundAddress = null; 091 datagramAcceptor = new NioDatagramAcceptor(); 092 socketAcceptor = new NioSocketAcceptor(); 093 094 ((DatagramSessionConfig) datagramAcceptor.getSessionConfig()) 095 .setReuseAddress(true); 096 ((NioSocketAcceptor) socketAcceptor).setReuseAddress(true); 097 098 // Find an available test port and bind to it. 099 boolean socketBound = false; 100 boolean datagramBound = false; 101 102 // Let's start from port #1 to detect possible resource leak 103 // because test will fail in port 1-1023 if user run this test 104 // as a normal user. 105 106 SocketAddress address = null; 107 108 // Find the first available port above 1024 109 port = AvailablePortFinder.getNextAvailable(1024); 110 111 socketBound = false; 112 datagramBound = false; 113 114 address = new InetSocketAddress(port); 115 116 try { 117 socketAcceptor.setHandler(new EchoProtocolHandler() { 118 @Override 119 public void sessionCreated(IoSession session) { 120 if (useSSL) { 121 try { 122 session.getFilterChain().addFirst( 123 "SSL", 124 new SslFilter(BogusSslContextFactory 125 .getInstance(true))); 126 } catch (GeneralSecurityException e) { 127 LOGGER.error("", e); 128 throw new RuntimeException(e); 129 } 130 } 131 } 132 133 // This is for TLS re-entrance test 134 @Override 135 public void messageReceived(IoSession session, Object message) 136 throws Exception { 137 if (!(message instanceof IoBuffer)) { 138 return; 139 } 140 141 IoBuffer buf = (IoBuffer) message; 142 143 buf.mark(); 144 145 if (session.getFilterChain().contains("SSL") 146 && buf.remaining() == 1 && buf.get() == (byte) '.') { 147 LOGGER.info("TLS Reentrance"); 148 ((SslFilter) session.getFilterChain().get("SSL")) 149 .startSsl(session); 150 151 // Send a response 152 buf.capacity(1); 153 buf.flip(); 154 session.setAttribute(SslFilter.DISABLE_ENCRYPTION_ONCE); 155 session.write(buf); 156 } else { 157 buf.reset(); 158 super.messageReceived(session, buf); 159 } 160 } 161 }); 162 163 socketAcceptor.bind(address); 164 socketBound = true; 165 166 datagramAcceptor.setHandler(new EchoProtocolHandler()); 167 datagramAcceptor.bind(address); 168 datagramBound = true; 169 } catch (IOException e) { 170 // Do nothing 171 } finally { 172 if (socketBound && !datagramBound) { 173 socketAcceptor.unbind(); 174 } 175 if (datagramBound && !socketBound) { 176 datagramAcceptor.unbind(); 177 } 178 } 179 180 // If there is no port available, test fails. 181 if (!socketBound || !datagramBound) { 182 throw new IOException("Cannot bind any test port."); 183 } 184 185 boundAddress = address; 186 LOGGER.info("Using port " + port + " for testing."); 187 } 188 189 @After 190 public void tearDown() throws Exception { 191 if (boundAddress != null) { 192 socketAcceptor.dispose(); 193 datagramAcceptor.dispose(); 194 } 195 } 196}