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