Home | History | Annotate | Download | only in tcp
      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