View Javadoc
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  import static org.junit.Assert.assertEquals;
22  
23  import java.io.IOException;
24  import java.net.InetSocketAddress;
25  import java.net.SocketAddress;
26  import java.security.GeneralSecurityException;
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.FilterEvent;
33  import org.apache.mina.filter.ssl.SslFilter;
34  import org.apache.mina.transport.socket.DatagramSessionConfig;
35  import org.apache.mina.transport.socket.nio.NioDatagramAcceptor;
36  import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
37  import org.apache.mina.util.AvailablePortFinder;
38  import org.junit.After;
39  import org.junit.Before;
40  import org.slf4j.Logger;
41  import org.slf4j.LoggerFactory;
42  
43  /**
44   * Tests echo server example.
45   *
46   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
47   */
48  public abstract class AbstractTest {
49      private final static Logger LOGGER = LoggerFactory.getLogger(AbstractTest.class);
50  
51      protected boolean useSSL;
52  
53      protected int port;
54  
55      protected SocketAddress boundAddress;
56  
57      protected IoAcceptor datagramAcceptor;
58  
59      protected IoAcceptor socketAcceptor;
60  
61      protected AbstractTest() {
62          // Do nothing
63      }
64  
65      protected static void isEquals(byte[] expected, byte[] actual) {
66          assertEquals(toString(expected), toString(actual));
67      }
68  
69      protected static void isEquals(IoBuffer expected, IoBuffer actual) {
70          assertEquals(toString(expected), toString(actual));
71      }
72  
73      protected static String toString(byte[] buf) {
74          StringBuilder str = new StringBuilder(buf.length * 4);
75          for (byte element : buf) {
76              str.append(element);
77              str.append(' ');
78          }
79          return str.toString();
80      }
81  
82      protected static String toString(IoBuffer buf) {
83          return buf.getHexDump();
84      }
85  
86      @Before
87      public void setUp() throws Exception {
88          // Disable SSL by default
89          useSSL = false;
90  
91          boundAddress = null;
92          datagramAcceptor = new NioDatagramAcceptor();
93          socketAcceptor = new NioSocketAcceptor();
94  
95          ((DatagramSessionConfig) datagramAcceptor.getSessionConfig())
96                  .setReuseAddress(true);
97          ((NioSocketAcceptor) socketAcceptor).setReuseAddress(true);
98  
99          // Find an available test port and bind to it.
100         boolean socketBound = false;
101         boolean datagramBound = false;
102 
103         // Let's start from port #1 to detect possible resource leak
104         // because test will fail in port 1-1023 if user run this test
105         // as a normal user.
106 
107         SocketAddress address = null;
108 
109         // Find the first available port above 1024
110         port = AvailablePortFinder.getNextAvailable(1024);
111 
112         socketBound = false;
113         datagramBound = false;
114 
115         address = new InetSocketAddress(port);
116 
117         try {
118             socketAcceptor.setHandler(new EchoProtocolHandler() {
119                 @Override
120                 public void sessionCreated(IoSession session) {
121                     if (useSSL) {
122                         try {
123                             session.getFilterChain().addFirst(
124                                     "SSL",
125                                     new SslFilter(BogusSslContextFactory
126                                             .getInstance(true)));
127                         } catch (GeneralSecurityException e) {
128                             LOGGER.error("", e);
129                             throw new RuntimeException(e);
130                         }
131                     }
132                 }
133 
134                 // This is for TLS re-entrance test
135                 @Override
136                 public void messageReceived(IoSession session, Object message)
137                         throws Exception {
138                     if (!(message instanceof IoBuffer)) {
139                         return;
140                     }
141 
142                     IoBuffer buf = (IoBuffer) message;
143                     
144                     buf.mark();
145 
146                     if (session.getFilterChain().contains("SSL")
147                             && buf.remaining() == 1 && buf.get() == (byte) '.') {
148                         LOGGER.info("TLS Reentrance");
149                         ((SslFilter) session.getFilterChain().get("SSL"))
150                                 .startSsl(session);
151 
152                         // Send a response
153                         buf.capacity(1);
154                         buf.flip();
155                         session.setAttribute(SslFilter.DISABLE_ENCRYPTION_ONCE);
156                         session.write(buf);
157                     } else {
158                         buf.reset();
159                         super.messageReceived(session, buf);
160                     }
161                 }
162                 
163                 public void fire(IoSession session, FilterEvent event) {
164                     System.out.println( event );
165                 }
166             });
167 
168             socketAcceptor.bind(address);
169             socketBound = true;
170 
171             datagramAcceptor.setHandler(new EchoProtocolHandler());
172             datagramAcceptor.bind(address);
173             datagramBound = true;
174         } catch (IOException e) {
175             // Do nothing
176         } finally {
177             if (socketBound && !datagramBound) {
178                 socketAcceptor.unbind();
179             }
180             if (datagramBound && !socketBound) {
181                 datagramAcceptor.unbind();
182             }
183         }
184 
185         // If there is no port available, test fails.
186         if (!socketBound || !datagramBound) {
187             throw new IOException("Cannot bind any test port.");
188         }
189 
190         boundAddress = address;
191         LOGGER.info("Using port " + port + " for testing.");
192     }
193 
194     @After
195     public void tearDown() throws Exception {
196         if (boundAddress != null) {
197             socketAcceptor.dispose();
198             datagramAcceptor.dispose();
199         }
200     }
201 }