001: /*
002: * Copyright (c) 2001 by The Regents of the University of California.
003: * All rights reserved.
004: *
005: * Permission to use, copy, modify, and distribute this software and its
006: * documentation for any purpose, without fee, and without written agreement is
007: * hereby granted, provided that the above copyright notice and the following
008: * two paragraphs appear in all copies of this software.
009: *
010: * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
011: * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
012: * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
013: * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
014: *
015: * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
016: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
017: * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
018: * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
019: * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
020: *
021: * Author: Jerrold Smith <jjsmith@pasteur.eecs.berkeley.edu>
022: *
023: */
024:
025: package seda.nbio;
026:
027: import java.io.*;
028: import java.net.*;
029:
030: /**
031: * A NonblockingDatagramSocket provides non-blocking UDP (datagram) I/O.
032: */
033: public class NonblockingDatagramSocket extends DatagramSocket implements
034: Selectable {
035:
036: NonblockingSocketImpl impl;
037: boolean is_connected;
038:
039: static {
040: NonblockingSocket.loadNativeLibrary();
041: }
042:
043: /**
044: * Create a NonblockingDatagramSocket bound to any available port.
045: */
046: public NonblockingDatagramSocket() throws IOException {
047: /* bind socket to any available port */
048: this (0, null);
049: }
050:
051: /**
052: * Create a NonblockingDatagramSocket bound to the given port.
053: */
054: public NonblockingDatagramSocket(int port) throws IOException {
055: this (port, null);
056: }
057:
058: /**
059: * Create a NonblockingDatagramSocket bound to the given port and
060: * the given local address.
061: */
062: public NonblockingDatagramSocket(int port, InetAddress laddr)
063: throws IOException {
064:
065: if (port < 0 || port > 0xFFFF) {
066: throw new IllegalArgumentException("port out range: "
067: + port);
068: }
069:
070: impl = new NonblockingSocketImpl();
071:
072: try {
073: is_connected = false;
074: impl.create(false);
075: // 'null' bind address means INADDR_ANY
076: impl.bind(laddr, port);
077: } catch (IOException e) {
078: close();
079: throw e;
080: }
081: }
082:
083: /**
084: * Close this NonblockingDatagramSocket.
085: */
086: public synchronized void close() {
087: try {
088: impl.close();
089: } catch (IOException e) {
090: // silently ignore exceptions to mimic java's close() for dgrams
091: }
092: }
093:
094: /**
095: * Connect this NonblockingDatagramSocket to the given address and port.
096: * All send() operations with a NULL 'sendTo' address will now send
097: * to this address by default. You may call connect() multiple times
098: * on a NonblockingDatagramSocket to change the default send address.
099: */
100: public void connect(InetAddress address, int port)
101: throws IllegalArgumentException {
102: if (port < 0 || port > 0xFFFF) {
103: throw new IllegalArgumentException("port out range:" + port);
104: }
105:
106: try {
107: impl.connect(address, port);
108: } catch (IOException e) {
109: System.err
110: .println("WARNING: NonblockingDatagramSocket.connect() - connect failed, exception is "
111: + e);
112: close();
113: //silently disgard exceptions
114: }
115: }
116:
117: /* Attempt to connect ot the given host and port, blocking until
118: * the connection is done
119: */
120: public void connect(String host, int port)
121: throws UnknownHostException {
122: connect(InetAddress.getByName(host), port);
123: }
124:
125: /* Disconnects a connected datagram socket. Does nothing if the
126: * socket isn't already connected.
127: */
128: public synchronized void disconnect() {
129: if (is_connected) {
130: try {
131: impl.disconnect();
132: } catch (IOException e) {
133: // XXX Ignore
134: }
135: is_connected = false;
136: }
137: }
138:
139: /**
140: * Return the remote address to which this socket is bound.
141: * Should be null if the socket hasn't been connected
142: * to anything.
143: */
144: public InetAddress getInetAddress() {
145: if (is_connected) {
146: return impl.getInetAddress();
147: } else {
148: return null;
149: }
150: }
151:
152: /**
153: * Return the local address to which this socket is bound.
154: */
155: public InetAddress getLocalAddress() {
156: try {
157: return InetAddress.getLocalHost();
158: } catch (Exception e) {
159: return null; // XXX MDW - Not quite right
160: }
161: }
162:
163: /**
164: * Return the remote port to which this socket is bound.
165: */
166: public int getPort() {
167: return impl.getPort();
168: }
169:
170: /**
171: * Return the local port to which this socket is bound.
172: */
173: public int getLocalPort() {
174: return impl.getLocalPort();
175: }
176:
177: /**
178: * Receive a datagram from this socket. When this method returns, the
179: * DatagramPacket's buffer is filled with the data received. The datagram
180: * packet also contains the sender's IP address, and the port number
181: * on the sender's machine.
182: *
183: * This method does not block if a datagram is not ready to be received.
184: * The length field of the datagram packet object contains the length
185: * of the received message, or is set to 0 if no packet was received.
186: * If the message is longer than the packet's length, the message is
187: * truncated.
188: *
189: * @return The size of the received packet, or 0 if no data was received.
190: */
191: public int nbReceive(DatagramPacket p) throws IOException {
192: return impl.receive(p);
193: }
194:
195: /**
196: * Receive a datagram from this socket. When this method returns, the
197: * given byte array is filled with the data received starting at the given
198: * offset with the given length. If the message is longer than the given
199: * length, the message is truncated.
200: *
201: * This method does not block if a datagram is not ready to be received.
202: *
203: * @return The size of the received packet, or 0 if no data was received.
204: */
205: public int nbReceive(byte[] data, int offset, int length)
206: throws IOException {
207: DatagramPacket p = new DatagramPacket(data, offset, length);
208: return nbReceive(p);
209: }
210:
211: /**
212: * Sends a datagram packet from this socket. The DatagramPacket includes
213: * information indicating the data to be sent, its length, the IP
214: * address of the remote host, and the port number on the remote host.
215: * This method does not block; it returns 0 if the packet could not
216: * be sent.
217: *
218: * @return The amount of data sent, or 0 if the packet could not be sent
219: * immediately.
220: */
221: public int nbSend(DatagramPacket p) throws IOException {
222: /* Java doesn't allow you to send pkts on a connected datagram
223: * socket to a different address, so mimic that
224: */
225: if (is_connected) {
226: if ((p.getAddress() != null)
227: && !p.getAddress().equals(impl.getInetAddress())) {
228: throw new IllegalArgumentException(
229: "DatagramPacket address does not equal address of connected NonblockingDatagramSocket");
230: }
231: }
232: return impl.send(p);
233: }
234:
235: /**
236: * Sends a datagram packet from this socket. This method constructs
237: * a temporary DatagramPacket from the given data, offset, length,
238: * address, and port, and calls nbSend(DatagramPacket p).
239: * This method does not block; it returns 0 if the packet could not
240: * be sent.
241: *
242: * @return The amount of data sent, or 0 if the packet could not be sent
243: * immediately.
244: */
245: public int nbSend(byte[] data, int offset, int length,
246: InetAddress addr, int port) throws IOException {
247: return nbSend(new DatagramPacket(data, offset, length, addr,
248: port));
249: }
250:
251: /**
252: * Sends a datagram packet from this socket. This method constructs
253: * a temporary DatagramPacket from the given data, offset, and length.
254: * This method may only be called on a connected socket; if called
255: * on an unconnected socket, an IllegalArgumentException is thrown.
256: * This method does not block; it returns 0 if the packet could not
257: * be sent.
258: *
259: * @return The amount of data sent, or 0 if the packet could not be sent
260: * immediately.
261: */
262: public int nbSend(byte[] data, int offset, int length)
263: throws IOException {
264: return nbSend(new DatagramPacket(data, offset, length));
265: }
266:
267: public int getReceiveBufferSize() throws SocketException {
268: throw new IllegalArgumentException("Not yet supported");
269: }
270:
271: public int getSendBufferSize() throws SocketException {
272: throw new IllegalArgumentException("Not yet supported");
273: }
274:
275: public void setReceiveBufferSize(int size) throws SocketException {
276: }
277:
278: public void setSendBufferSize(int size) throws SocketException {
279: throw new IllegalArgumentException("Not yet supported");
280: }
281:
282: /**
283: * This method is provided for convenience and mimics blocking behavior
284: * by invoking the nonblocking nbSend() operation. If the packet could
285: * not be immediately sent it is simply dropped (because this is a UDP
286: * socket this behavior is consistent with the lack of reliability in UDP).
287: *
288: * <p>Use of this method is not recommended and is provided only
289: * for compatibility with java.net.DatagramSocket.
290: */
291: public void send(DatagramPacket p) throws IOException {
292: nbSend(p);
293: }
294:
295: /**
296: * This method is provided for convenience and mimics blocking behavior
297: * by invoking the nonblocking nbReceive() operation. If no packet could
298: * be immediately received it returns immediately with a received packet
299: * length of 0.
300: *
301: * <p>Use of this method is not recommended and is provided only
302: * for compatibility with java.net.DatagramSocket.
303: */
304: public void receive(DatagramPacket p) throws IOException {
305: nbReceive(p);
306: }
307:
308: }
|