View Javadoc

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