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: package org.apache.mina.example.echoserver;
021:
022: import java.net.InetSocketAddress;
023:
024: import junit.framework.Assert;
025:
026: import org.apache.mina.common.ConnectFuture;
027: import org.apache.mina.common.IoBuffer;
028: import org.apache.mina.common.IoConnector;
029: import org.apache.mina.common.IoHandlerAdapter;
030: import org.apache.mina.common.IoSession;
031: import org.apache.mina.common.RuntimeIoException;
032: import org.apache.mina.common.WriteException;
033: import org.apache.mina.common.WriteFuture;
034: import org.apache.mina.example.echoserver.ssl.BogusSslContextFactory;
035: import org.apache.mina.filter.ssl.SslFilter;
036: import org.apache.mina.transport.socket.nio.NioDatagramConnector;
037: import org.apache.mina.transport.socket.nio.NioSocketConnector;
038: import org.apache.mina.util.AvailablePortFinder;
039: import org.slf4j.Logger;
040: import org.slf4j.LoggerFactory;
041:
042: /**
043: * Tests echo server example.
044: *
045: * @author The Apache MINA Project (dev@mina.apache.org)
046: * @version $Rev:448075 $, $Date:2006-09-20 05:26:53Z $
047: */
048: public class ConnectorTest extends AbstractTest {
049: private final static Logger logger = LoggerFactory
050: .getLogger(ConnectorTest.class);
051:
052: private static final int TIMEOUT = 10000; // 10 seconds
053:
054: private final int COUNT = 10;
055:
056: private final int DATA_SIZE = 16;
057:
058: private EchoConnectorHandler handler;
059: private SslFilter connectorSSLFilter;
060:
061: public ConnectorTest() {
062: }
063:
064: @Override
065: protected void setUp() throws Exception {
066: super .setUp();
067: handler = new EchoConnectorHandler();
068: connectorSSLFilter = new SslFilter(BogusSslContextFactory
069: .getInstance(false));
070: connectorSSLFilter.setUseClientMode(true); // set client mode
071: }
072:
073: public void testTCP() throws Exception {
074: IoConnector connector = new NioSocketConnector();
075: testConnector(connector);
076: }
077:
078: public void testTCPWithSSL() throws Exception {
079: useSSL = true;
080: // Create a connector
081: IoConnector connector = new NioSocketConnector();
082:
083: // Add an SSL filter to connector
084: connector.getFilterChain().addLast("SSL", connectorSSLFilter);
085: testConnector(connector);
086: }
087:
088: public void testUDP() throws Exception {
089: IoConnector connector = new NioDatagramConnector();
090: testConnector(connector);
091: }
092:
093: private void testConnector(IoConnector connector) throws Exception {
094: connector.setHandler(handler);
095:
096: System.out.println("* Without localAddress");
097: testConnector(connector, false);
098:
099: System.out.println("* With localAddress");
100: testConnector(connector, true);
101: }
102:
103: private void testConnector(IoConnector connector,
104: boolean useLocalAddress) throws Exception {
105: IoSession session = null;
106: if (!useLocalAddress) {
107: ConnectFuture future = connector
108: .connect(new InetSocketAddress("127.0.0.1", port));
109: future.awaitUninterruptibly();
110: session = future.getSession();
111: } else {
112: int clientPort = port;
113: for (int i = 0; i < 65536; i++) {
114: clientPort = AvailablePortFinder
115: .getNextAvailable(clientPort + 1);
116: try {
117: ConnectFuture future = connector.connect(
118: new InetSocketAddress("127.0.0.1", port),
119: new InetSocketAddress(clientPort));
120: future.awaitUninterruptibly();
121: session = future.getSession();
122: break;
123: } catch (RuntimeIoException e) {
124: // Try again until we succeed to bind.
125: }
126: }
127:
128: if (session == null) {
129: Assert
130: .fail("Failed to find out an appropriate local address.");
131: }
132: }
133:
134: // Run a basic connector test.
135: testConnector0(session);
136:
137: // Send closeNotify to test TLS closure if it is TLS connection.
138: if (useSSL) {
139: connectorSSLFilter.stopSsl(session).awaitUninterruptibly();
140:
141: System.out
142: .println("-------------------------------------------------------------------------------");
143: // Test again after we finished TLS session.
144: testConnector0(session);
145:
146: System.out
147: .println("-------------------------------------------------------------------------------");
148:
149: // Test if we can enter TLS mode again.
150: //// Send StartTLS request.
151: handler.readBuf.clear();
152: IoBuffer buf = IoBuffer.allocate(1);
153: buf.put((byte) '.');
154: buf.flip();
155: session.write(buf).awaitUninterruptibly();
156:
157: //// Wait for StartTLS response.
158: waitForResponse(handler, 1);
159:
160: handler.readBuf.flip();
161: Assert.assertEquals(1, handler.readBuf.remaining());
162: Assert.assertEquals((byte) '.', handler.readBuf.get());
163:
164: // Now start TLS connection
165: Assert.assertTrue(connectorSSLFilter.startSsl(session));
166: testConnector0(session);
167: }
168:
169: session.close().awaitUninterruptibly();
170: }
171:
172: private void testConnector0(IoSession session)
173: throws InterruptedException {
174: EchoConnectorHandler handler = (EchoConnectorHandler) session
175: .getHandler();
176: IoBuffer readBuf = handler.readBuf;
177: readBuf.clear();
178: WriteFuture writeFuture = null;
179: for (int i = 0; i < COUNT; i++) {
180: IoBuffer buf = IoBuffer.allocate(DATA_SIZE);
181: buf.limit(DATA_SIZE);
182: fillWriteBuffer(buf, i);
183: buf.flip();
184:
185: writeFuture = session.write(buf);
186:
187: if (session.getService().getTransportMetadata()
188: .isConnectionless()) {
189: // This will align message arrival order in connectionless transport types
190: waitForResponse(handler, (i + 1) * DATA_SIZE);
191: }
192: }
193:
194: writeFuture.awaitUninterruptibly();
195:
196: waitForResponse(handler, DATA_SIZE * COUNT);
197:
198: // Assert data
199: //// Please note that BufferOverflowException can be thrown
200: //// in SocketIoProcessor if there was a read timeout because
201: //// we share readBuf.
202: readBuf.flip();
203: logger.info("readBuf: " + readBuf);
204: Assert.assertEquals(DATA_SIZE * COUNT, readBuf.remaining());
205: IoBuffer expectedBuf = IoBuffer.allocate(DATA_SIZE * COUNT);
206: for (int i = 0; i < COUNT; i++) {
207: expectedBuf.limit((i + 1) * DATA_SIZE);
208: fillWriteBuffer(expectedBuf, i);
209: }
210: expectedBuf.position(0);
211:
212: assertEquals(expectedBuf, readBuf);
213: }
214:
215: private void waitForResponse(EchoConnectorHandler handler, int bytes)
216: throws InterruptedException {
217: for (int j = 0; j < TIMEOUT / 10; j++) {
218: if (handler.readBuf.position() >= bytes) {
219: break;
220: }
221: Thread.sleep(10);
222: }
223:
224: Assert.assertEquals(bytes, handler.readBuf.position());
225: }
226:
227: private void fillWriteBuffer(IoBuffer writeBuf, int i) {
228: while (writeBuf.remaining() > 0) {
229: writeBuf.put((byte) i++);
230: }
231: }
232:
233: public static void main(String[] args) {
234: junit.textui.TestRunner.run(ConnectorTest.class);
235: }
236:
237: private static class EchoConnectorHandler extends IoHandlerAdapter {
238: private final IoBuffer readBuf = IoBuffer.allocate(1024);
239:
240: private EchoConnectorHandler() {
241: readBuf.setAutoExpand(true);
242: }
243:
244: @Override
245: public void messageReceived(IoSession session, Object message) {
246: readBuf.put((IoBuffer) message);
247: }
248:
249: @Override
250: public void messageSent(IoSession session, Object message) {
251: }
252:
253: @Override
254: public void exceptionCaught(IoSession session, Throwable cause) {
255: logger.warn("Unexpected exception.", cause);
256: if (cause instanceof WriteException) {
257: WriteException e = (WriteException) cause;
258: logger.warn("Failed write requests: {}", e
259: .getRequests());
260: }
261: }
262: }
263: }
|