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 33 package com.jme3.network.kernel.tcp; 34 35 import com.jme3.network.kernel.Connector; 36 import com.jme3.network.kernel.ConnectorException; 37 import java.io.IOException; 38 import java.io.InputStream; 39 import java.io.OutputStream; 40 import java.net.InetAddress; 41 import java.net.Socket; 42 import java.net.SocketAddress; 43 import java.nio.ByteBuffer; 44 import java.util.concurrent.atomic.AtomicBoolean; 45 46 47 /** 48 * A straight forward socket-based connector implementation that 49 * does not use any separate threading. It relies completely on 50 * the buffering in the OS network layer. 51 * 52 * @version $Revision: 8843 $ 53 * @author Paul Speed 54 */ 55 public class SocketConnector implements Connector 56 { 57 private Socket sock; 58 private InputStream in; 59 private OutputStream out; 60 private SocketAddress remoteAddress; 61 private byte[] buffer = new byte[65535]; 62 private AtomicBoolean connected = new AtomicBoolean(false); 63 64 public SocketConnector( InetAddress address, int port ) throws IOException 65 { 66 this.sock = new Socket(address, port); 67 remoteAddress = sock.getRemoteSocketAddress(); // for info purposes 68 69 // Disable Nagle's buffering so data goes out when we 70 // put it there. 71 sock.setTcpNoDelay(true); 72 73 in = sock.getInputStream(); 74 out = sock.getOutputStream(); 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 try { 96 Socket temp = sock; 97 sock = null; 98 connected.set(false); 99 temp.close(); 100 } catch( IOException e ) { 101 throw new ConnectorException( "Error closing socket for:" + remoteAddress, e ); 102 } 103 } 104 105 public boolean available() 106 { 107 checkClosed(); 108 try { 109 return in.available() > 0; 110 } catch( IOException e ) { 111 throw new ConnectorException( "Error retrieving data availability for:" + remoteAddress, e ); 112 } 113 } 114 115 public ByteBuffer read() 116 { 117 checkClosed(); 118 119 try { 120 // Read what we can 121 int count = in.read(buffer); 122 if( count < 0 ) { 123 // Socket is closed 124 close(); 125 return null; 126 } 127 128 // Wrap it in a ByteBuffer for the caller 129 return ByteBuffer.wrap( buffer, 0, count ); 130 } catch( IOException e ) { 131 if( !connected.get() ) { 132 // Nothing to see here... just move along 133 return null; 134 } 135 throw new ConnectorException( "Error reading from connection to:" + remoteAddress, e ); 136 } 137 } 138 139 public void write( ByteBuffer data ) 140 { 141 checkClosed(); 142 143 try { 144 out.write(data.array(), data.position(), data.remaining()); 145 } catch( IOException e ) { 146 throw new ConnectorException( "Error writing to connection:" + remoteAddress, e ); 147 } 148 } 149 150 } 151