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