1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  package org.apache.mina.example.echoserver;
21  
22  import java.io.IOException;
23  import java.net.InetSocketAddress;
24  import java.net.SocketAddress;
25  
26  import junit.framework.TestCase;
27  
28  import org.apache.mina.core.buffer.IoBuffer;
29  import org.apache.mina.core.service.IoAcceptor;
30  import org.apache.mina.core.session.IoSession;
31  import org.apache.mina.example.echoserver.ssl.BogusSslContextFactory;
32  import org.apache.mina.filter.ssl.SslFilter;
33  import org.apache.mina.transport.socket.DatagramSessionConfig;
34  import org.apache.mina.transport.socket.nio.NioDatagramAcceptor;
35  import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
36  import org.apache.mina.util.AvailablePortFinder;
37  import org.slf4j.Logger;
38  import org.slf4j.LoggerFactory;
39  
40  /**
41   * Tests echo server example.
42   *
43   * @author The Apache MINA Project (dev@mina.apache.org)
44   * @version $Rev:448075 $, $Date:2006-09-20 05:26:53Z $
45   */
46  public abstract class AbstractTest extends TestCase {
47      private final Logger logger = LoggerFactory.getLogger(getClass());
48  
49      protected boolean useSSL;
50  
51      protected int port;
52  
53      protected SocketAddress boundAddress;
54  
55      protected IoAcceptor datagramAcceptor;
56  
57      protected IoAcceptor socketAcceptor;
58  
59      protected AbstractTest() {
60      }
61  
62      protected static void assertEquals(byte[] expected, byte[] actual) {
63          assertEquals(toString(expected), toString(actual));
64      }
65  
66      protected static void assertEquals(IoBuffer expected, IoBuffer actual) {
67          assertEquals(toString(expected), toString(actual));
68      }
69  
70      protected static String toString(byte[] buf) {
71          StringBuffer str = new StringBuffer(buf.length * 4);
72          for (byte element : buf) {
73              str.append(element);
74              str.append(' ');
75          }
76          return str.toString();
77      }
78  
79      protected static String toString(IoBuffer buf) {
80          return buf.getHexDump();
81      }
82  
83      @Override
84      protected void setUp() throws Exception {
85          // Disable SSL by default
86          useSSL = false;
87          final SslFilter sslFilter = new SslFilter(BogusSslContextFactory
88                  .getInstance(true));
89  
90          boundAddress = null;
91          datagramAcceptor = new NioDatagramAcceptor();
92          socketAcceptor = new NioSocketAcceptor();
93  
94          ((DatagramSessionConfig) datagramAcceptor.getSessionConfig())
95                  .setReuseAddress(true);
96          ((NioSocketAcceptor) socketAcceptor).setReuseAddress(true);
97  
98          // Find an available test port and bind to it.
99          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                         session.getFilterChain().addFirst("SSL", sslFilter);
122                     }
123                 }
124 
125                 // This is for TLS re-entrance test
126                 @Override
127                 public void messageReceived(IoSession session,
128                         Object message) throws Exception {
129                     if (!(message instanceof IoBuffer)) {
130                         return;
131                     }
132 
133                     IoBuffer buf = (IoBuffer) message;
134                     if (session.getFilterChain().contains("SSL")
135                             && buf.remaining() == 1
136                             && buf.get() == (byte) '.') {
137                         logger.info("TLS Reentrance");
138                         ((SslFilter) session.getFilterChain().get("SSL"))
139                                 .startSsl(session);
140 
141                         // Send a response
142                         buf = IoBuffer.allocate(1);
143                         buf.put((byte) '.');
144                         buf.flip();
145                         session
146                                 .setAttribute(SslFilter.DISABLE_ENCRYPTION_ONCE);
147                         session.write(buf);
148                     } else {
149                         super.messageReceived(session, message);
150                     }
151                 }
152             });
153 
154             socketAcceptor.bind(address);
155             socketBound = true;
156 
157             datagramAcceptor.setHandler(new EchoProtocolHandler());
158             datagramAcceptor.bind(address);
159             datagramBound = true;
160         } catch (IOException e) {
161             // Do nothing
162         } finally {
163             if (socketBound && !datagramBound) {
164                 socketAcceptor.unbind();
165             }
166             if (datagramBound && !socketBound) {
167                 datagramAcceptor.unbind();
168             }
169         }
170 
171         // If there is no port available, test fails.
172         if (!socketBound || !datagramBound) {
173             throw new IOException("Cannot bind any test port.");
174         }
175 
176         boundAddress = address;
177         System.out.println("Using port " + port + " for testing.");
178     }
179 
180     @Override
181     protected void tearDown() throws Exception {
182         if (boundAddress != null) {
183             socketAcceptor.dispose();
184             datagramAcceptor.dispose();
185         }
186     }
187 }