View Javadoc

1   /*
2    * Copyright (c) 1998-2002 The Jgroup Team.
3    *
4    * This program is free software; you can redistribute it and/or modify
5    * it under the terms of the GNU Lesser General Public License version 2 as
6    * published by the Free Software Foundation.
7    *
8    * This program is distributed in the hope that it will be useful,
9    * but WITHOUT ANY WARRANTY; without even the implied warranty of
10   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11   * GNU Lesser General Public License for more details.
12   *
13   * You should have received a copy of the GNU Lesser General Public License
14   * along with this program; if not, write to the Free Software
15   * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16   *
17   */
18  
19  package jgroup.relacs.mss;
20  
21  import java.io.IOException;
22  import java.net.DatagramPacket;
23  import java.net.DatagramSocket;
24  import java.net.SocketException;
25  
26  import jgroup.core.EndPoint;
27  
28  import org.apache.log4j.Logger;
29  import org.apache.log4j.NDC;
30  
31  /**
32   *  The <code>UnicastNetworkInterface</code> class implements a
33   *  unicast version of the network interface.
34   *
35   *  @author Salvatore Cammarata
36   *  @author Hein Meling
37   *  @since Jgroup 1.2
38   */
39  final class UnicastNetworkInterface
40    extends Thread
41    implements NetworkInterface, MssConstants
42  {
43  
44    ////////////////////////////////////////////////////////////////////////////////////////////
45    // Logger
46    ////////////////////////////////////////////////////////////////////////////////////////////
47  
48    /** Obtain logger for this class */
49    private static final Logger log = Logger.getLogger(UnicastNetworkInterface.class);
50  
51  
52    ////////////////////////////////////////////////////////////////////////////////////////////
53    // Fields
54    ////////////////////////////////////////////////////////////////////////////////////////////
55  
56    /** Upper layer */
57    private NIListener niListener;
58  
59    /** UDP Socket */
60    private DatagramSocket socket;
61  
62    /** Receive buffer length */
63    private int bufferlen;
64  
65    /** True when the thread should continue to run */
66    private boolean carryOn;
67  
68  
69    ////////////////////////////////////////////////////////////////////////////////////////////
70    // Constructor
71    ////////////////////////////////////////////////////////////////////////////////////////////
72  
73    /**
74     *  Constructs and starts the unicast network interface layer.
75     *
76     *  @param name
77     *    Thread identifier.
78     *  @param niListener
79     *    Reference to the upper listener layer through which multicast
80     *    receive events are passed as upcall invocations.
81     *  @param endpoint
82     *    Endpoint socket address and port.
83     *  @param bufferlen
84     *    Size of receive buffer.
85     *  @exception IOException
86     *    Raised if the unicast socket could not be initialized.
87     */
88    UnicastNetworkInterface(String name, NIListener niListener, EndPoint endpoint, int bufferlen)
89      throws IOException
90    {
91      /* Initialize thread */
92      super(name);
93      this.setPriority(NI_PRIORITY);
94      this.setDaemon(true);
95  
96      this.niListener = niListener;
97      this.bufferlen  = bufferlen;
98      this.carryOn    = true;
99  
100     /* Initialize socket */
101     boolean partitionSimulator = Boolean.getBoolean("jgroup.simulator");
102     try {
103       if (partitionSimulator) {
104         socket = new UnreliableDatagramSocket(endpoint.getPort(), endpoint.getAddress());
105       } else {
106         if (log.isDebugEnabled())
107           log.debug("Trying to create a datagram socket at  " + endpoint.getAddress() + " ." +endpoint.getPort() );     
108         socket = new DatagramSocket(endpoint.getPort(), endpoint.getAddress());
109       }  
110     } catch (SocketException e) {
111       if (log.isDebugEnabled())
112         log.warn("Error initializing unicast socket at " + endpoint, e);
113       throw new IOException("Error initializing unicast socket: " + endpoint + "\n" ); 
114     }
115     if (log.isDebugEnabled())
116       log.debug("Unicast socket initialized: " + endpoint + " " + bufferlen);
117   }
118 
119 
120   ////////////////////////////////////////////////////////////////////////////////////////////
121   // Methods from NetworkInterface
122   ////////////////////////////////////////////////////////////////////////////////////////////
123 
124   /*
125    *  This operation is not supported by the unicast network interface,
126    *  because a host does not send a message to itself through the
127    *  network interface.  If a host is running multiple daemons on
128    *  different ports (JVMs), the method below can be used by specifying
129    *  the endpoint.  This is possible since the endpoint contains both
130    *  the internet address and the port.
131    */
132   public void send(byte[] buffer, int buflen)
133   {
134     throw new UnsupportedOperationException();
135   }
136 
137 
138   // Javadoc comment inherited by NetworkInterface
139   public void send(EndPoint dest, byte[] buffer, int buflen)
140   {
141     DatagramPacket packet =
142       new DatagramPacket(buffer, buflen, dest.getAddress(), dest.getPort());
143 
144     try {
145       socket.send(packet);
146     } catch (IOException e) {
147       log.warn("Error sending packet to " + dest, e);
148     }
149   }
150 
151 
152   // Javadoc comment inherited by NetworkInterface
153   public void doStart()
154   {
155     start();
156   }
157 
158 
159   // Javadoc comment inherited by NetworkInterface
160   public void doStop() 
161   {
162     carryOn = false;
163   }
164 
165 
166   ////////////////////////////////////////////////////////////////////////////////////////////
167   // Methods from Object
168   ////////////////////////////////////////////////////////////////////////////////////////////
169 
170   /**
171    *  Clean up system resources used by this class.  This method will be
172    *  invoked when there are no more references to this object, and thus
173    *  it should be garbage collected.
174    */
175   protected void finalize() 
176   {
177     carryOn = false;
178     if (socket != null) {   
179       socket.close();      
180       socket = null;       
181     }
182   }
183 
184 
185   ////////////////////////////////////////////////////////////////////////////////////////////
186   // Methods from Thread
187   ////////////////////////////////////////////////////////////////////////////////////////////
188 
189   /**
190    * Run method of the thread. It blocks until a Datagram packet is received
191    * through the net.
192    */
193   public void run()
194   {
195     while (carryOn) {
196       try {
197         byte[] buf = new byte[bufferlen];
198         DatagramPacket packet = new DatagramPacket(buf, bufferlen);
199         socket.receive(packet);
200         if (log.isDebugEnabled()) {
201           String senderName = packet.getAddress().getHostName();
202           NDC.push(senderName);
203           log.debug("unicast packet.length=" + packet.getLength() + ", sender=" + senderName);
204         }
205         niListener.rnotify(packet);
206       } catch (IOException e) {
207         log.warn("Error receiving packet", e);
208       } finally {
209         if (log.isDebugEnabled())
210           NDC.pop();
211       }
212     }
213     /* The thread was stopped, cleaning up system resources. */
214     this.finalize();
215   }
216 
217 } // END UnicastNetworkInterface