1/* 2 * Copyright (c) 2011 jMonkeyEngine 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33package com.jme3.network.kernel.udp; 34 35import com.jme3.network.kernel.Connector; 36import com.jme3.network.kernel.ConnectorException; 37import java.io.IOException; 38import java.net.*; 39import java.nio.ByteBuffer; 40import java.util.concurrent.atomic.AtomicBoolean; 41 42 43/** 44 * A straight forward datagram socket-based UDP connector 45 * implementation. 46 * 47 * @version $Revision: 8843 $ 48 * @author Paul Speed 49 */ 50public class UdpConnector implements Connector 51{ 52 private DatagramSocket sock = new DatagramSocket(); 53 private SocketAddress remoteAddress; 54 private byte[] buffer = new byte[65535]; 55 private AtomicBoolean connected = new AtomicBoolean(false); 56 57 /** 58 * In order to provide proper available() checking, we 59 * potentially queue one datagram. 60 */ 61 private DatagramPacket pending; 62 63 /** 64 * Creates a new UDP connection that send datagrams to the 65 * specified address and port. 66 */ 67 public UdpConnector( InetAddress remote, int remotePort ) throws IOException 68 { 69 InetSocketAddress localSocketAddress = new InetSocketAddress(0); 70 this.sock = new DatagramSocket( localSocketAddress ); 71 remoteAddress = new InetSocketAddress( remote, remotePort ); 72 73 // Setup to receive only from the remote address 74 sock.connect( remoteAddress ); 75 76 connected.set(true); 77 } 78 79 protected void checkClosed() 80 { 81 if( sock == null ) 82 throw new ConnectorException( "Connection is closed:" + remoteAddress ); 83 } 84 85 public boolean isConnected() 86 { 87 if( sock == null ) 88 return false; 89 return sock.isConnected(); 90 } 91 92 public void close() 93 { 94 checkClosed(); 95 DatagramSocket temp = sock; 96 sock = null; 97 connected.set(false); 98 temp.close(); 99 } 100 101 /** 102 * This always returns false since the simple DatagramSocket usage 103 * cannot be run in a non-blocking way. 104 */ 105 public boolean available() 106 { 107 // It would take a separate thread or an NIO Selector based implementation to get this 108 // to work. If a polling strategy is never employed by callers then it doesn't 109 // seem worth it to implement all of that just for this method. 110 checkClosed(); 111 return false; 112 } 113 114 public ByteBuffer read() 115 { 116 checkClosed(); 117 118 try { 119 DatagramPacket packet = new DatagramPacket( buffer, buffer.length ); 120 sock.receive(packet); 121 122 // Wrap it in a ByteBuffer for the caller 123 return ByteBuffer.wrap( buffer, 0, packet.getLength() ); 124 } catch( IOException e ) { 125 if( !connected.get() ) { 126 // Nothing to see here... just move along 127 return null; 128 } 129 throw new ConnectorException( "Error reading from connection to:" + remoteAddress, e ); 130 } 131 } 132 133 public void write( ByteBuffer data ) 134 { 135 checkClosed(); 136 137 try { 138 DatagramPacket p = new DatagramPacket( data.array(), data.position(), data.remaining(), 139 remoteAddress ); 140 sock.send(p); 141 } catch( IOException e ) { 142 throw new ConnectorException( "Error writing to connection:" + remoteAddress, e ); 143 } 144 } 145} 146 147