View Javadoc

1   /*
2    * $Id: LingerExperimentMule2067TestCase.java 20321 2010-11-24 15:21:24Z dfeist $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.transport.tcp.issues;
12  
13  import org.mule.tck.AbstractMuleTestCase;
14  
15  import java.io.IOException;
16  import java.net.InetSocketAddress;
17  import java.net.ServerSocket;
18  import java.net.Socket;
19  
20  import org.apache.commons.logging.Log;
21  import org.apache.commons.logging.LogFactory;
22  
23  /**
24   * Are the "address already in use" errors coming from lingering sockets?
25   *
26   * We see "address already in use" errors when trying to re-use sockets very quickly,
27   * but the tests below don't give much information, except that:
28   * - data needs to be sent
29   * - explicitly setting or disabling the SO_LINGER value has little effect
30   */
31  public class LingerExperimentMule2067TestCase extends AbstractMuleTestCase
32  {
33  
34      private static final int NO_LINGER = -1;
35      private static final int HARD_CLOSE = 0;
36      private static final int NO_WAIT = -1;
37      private static final int PORT = 65432;
38  
39      private Log logger = LogFactory.getLog(getClass());
40  
41      public void testInoffensive() throws IOException
42      {
43          // this shows it's not simple open/close that causes a problem
44          openCloseServer(1000, PORT); // ok
45          openCloseClientServer(1000, PORT, NO_LINGER, NO_LINGER); // ok
46      }
47  
48      public void testThisShowsTheProblem() throws IOException
49      {
50          // this shows a problem with repeated open/close with a client/server pair
51          repeatOpenCloseClientServer(10, 10, PORT, 1000); // ok
52          repeatOpenCloseClientServer(10, 10, PORT, 100); // ok
53          repeatOpenCloseClientServer(10, 10, PORT, 10); // ok
54          repeatOpenCloseClientServer(10, 10, PORT, 1); // ok
55          repeatOpenCloseClientServer(10, 10, PORT, 0); // intermittent
56          repeatOpenCloseClientServer(10, 10, PORT, NO_WAIT); // intermittent
57      }
58  
59      public void testWithClientLinger() throws IOException
60      {
61          // this shows it's not simple client linger time, or the later tests would always fail
62          repeatOpenCloseClientServer(10, 10, PORT, NO_WAIT, NO_LINGER); // intermittent, as above
63          repeatOpenCloseClientServer(10, 10, PORT, 100, 1); // ok
64          repeatOpenCloseClientServer(10, 10, PORT, 10, 1); // intermittent
65          repeatOpenCloseClientServer(10, 10, PORT, 100, 2); // intermittent
66          repeatOpenCloseClientServer(10, 10, PORT, 100, 30); // intermittent
67          // hard close on client doesn't help
68          repeatOpenCloseClientServer(10, 10, PORT, 10, HARD_CLOSE); // intermittent
69          repeatOpenCloseClientServer(10, 10, PORT, NO_WAIT, HARD_CLOSE); // intermittent
70      }
71  
72      public void testWithServerLinger() throws IOException
73      {
74          // server linger seems to improve things(?!), but still have problems
75          repeatOpenCloseClientServer(10, 10, PORT, 10, NO_LINGER, 1); // ok
76          repeatOpenCloseClientServer(10, 10, PORT, 10, NO_LINGER, 1); // ok
77          repeatOpenCloseClientServer(10, 10, PORT, 10, NO_LINGER, 2); // ok
78          repeatOpenCloseClientServer(10, 10, PORT, 10, NO_LINGER, 30); // ok
79          repeatOpenCloseClientServer(10, 10, PORT, NO_WAIT, NO_LINGER, 1); // intermittent
80      }
81  
82      public void testHardClose() throws IOException
83      {
84          // this gives (very?) occasional "already in use" and also a "connection reset by peer"
85          // at the client, due to server closing so quickly
86          repeatOpenCloseClientServer(10, 10, PORT, NO_WAIT, HARD_CLOSE, HARD_CLOSE); // intermittent
87      }
88  
89      protected void openCloseServer(int numberOfSockets, int port) throws IOException
90      {
91          for (int i = 0; i < numberOfSockets; i++)
92          {
93              ServerSocket socket = new ServerSocket(port);
94              socket.close();
95          }
96      }
97  
98      protected void repeatOpenCloseClientServer(int numberOfRepeats, int numberOfConnections, int port, long pause)
99              throws IOException
100     {
101         repeatOpenCloseClientServer(numberOfRepeats, numberOfConnections, port, pause, NO_LINGER);
102     }
103 
104     protected void repeatOpenCloseClientServer(int numberOfRepeats, int numberOfConnections, int port,
105                                                long pause, int clientLinger)
106             throws IOException
107     {
108         repeatOpenCloseClientServer(numberOfRepeats, numberOfConnections, port, pause, clientLinger, NO_LINGER);
109     }
110 
111     protected void repeatOpenCloseClientServer(int numberOfRepeats, int numberOfConnections, int port,
112                                                long pause, int clientLinger, int serverLinger)
113             throws IOException
114     {
115         logger.info("Repeating openCloseClientServer with pauses of " + pause + " ms and lingers of "
116                 + clientLinger + "/" + serverLinger + " s (client/server)");
117         for (int i = 0; i < numberOfRepeats; i++)
118         {
119             if (0 != i && pause != NO_WAIT)
120             {
121                 try
122                 {
123                     synchronized(this)
124                     {
125                         if (pause > 0)
126                         {
127                             this.wait(pause);
128                         }
129                     }
130                 }
131                 catch (InterruptedException e)
132                 {
133                     // ignore
134                 }
135             }
136             openCloseClientServer(numberOfConnections, port, clientLinger, serverLinger);
137         }
138     }
139 
140     protected void openCloseClientServer(int numberOfConnections, int port, int clientLinger, int serverLinger)
141             throws IOException
142     {
143         Server server = new Server(port, serverLinger);
144         try
145         {
146             new Thread(server).start();
147             for (int i = 0; i < numberOfConnections; i++)
148             {
149                 logger.debug("opening socket " + i);
150                 Socket client = new Socket("localhost", port);
151                 if (NO_LINGER != clientLinger)
152                 {
153                     client.setSoLinger(true, clientLinger);
154                 }
155                 client.close();
156             }
157         }
158         finally
159         {
160             server.close();
161         }
162     }
163 
164     protected static class Server implements Runnable
165     {
166 
167         private Log logger = LogFactory.getLog(getClass());
168         private ServerSocket server;
169         private int linger;
170 
171         public Server(int port, int linger) throws IOException
172         {
173             this.linger = linger;
174             server = new ServerSocket();
175             server.bind(new InetSocketAddress("localhost", port));
176         }
177 
178         public void run()
179         {
180             try
181             {
182                 while (true)
183                 {
184                     Socket socket = server.accept();
185                     if (NO_LINGER != linger)
186                     {
187                         socket.setSoLinger(true, linger);
188                     }
189                     socket.close();
190                 }
191             }
192             catch (Exception e)
193             {
194                 logger.debug("Expected - dirty closedown: " + e);
195             }
196         }
197 
198         public void close() throws IOException
199         {
200             server.close();
201             server = null;
202         }
203     }
204 
205 }