Package org.jwebsocket.tcp.connectors

Source Code of org.jwebsocket.tcp.connectors.TCPConnector$ClientProcessor

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.jwebsocket.tcp.connectors;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.Arrays;
import org.apache.log4j.Logger;
import org.jwebsocket.api.EngineConfiguration;
import org.jwebsocket.api.WebSocketPacket;
import org.jwebsocket.api.WebSocketConnector;
import org.jwebsocket.api.WebSocketEngine;
import org.jwebsocket.config.JWebSocketCommonConstants;
import org.jwebsocket.connectors.BaseConnector;
import org.jwebsocket.kit.CloseReason;
import org.jwebsocket.kit.RawPacket;
import org.jwebsocket.logging.Logging;

/**
* Implementation of the jWebSocket TCP socket connector.
* @author aschulze
*/
public class TCPConnector extends BaseConnector {

  private static Logger mLog = Logging.getLogger(TCPConnector.class);
  private InputStream mIn = null;
  private OutputStream mOut = null;
  private Socket mClientSocket = null;
  private boolean mIsRunning = false;
  private CloseReason mCloseReason = CloseReason.TIMEOUT;

  /**
   * creates a new TCP connector for the passed engine using the passed
   * client socket. Usually connectors are instantiated by their engine
   * only, not by the application.
   * @param aEngine
   * @param aClientSocket
   */
  public TCPConnector(WebSocketEngine aEngine, Socket aClientSocket) {
    super(aEngine);
    mClientSocket = aClientSocket;
    try {
      mIn = mClientSocket.getInputStream();
      mOut = new PrintStream(mClientSocket.getOutputStream(), true, "UTF-8");
    } catch (Exception ex) {
      mLog.error(ex.getClass().getSimpleName()
          + " instantiating " + getClass().getSimpleName()
          + ": " + ex.getMessage());
    }
  }

  @Override
  public void startConnector() {
    int lPort = -1;
    int lTimeout = -1;
    try {
      lPort = mClientSocket.getPort();
      lTimeout = mClientSocket.getSoTimeout();
    } catch (Exception ex) {
    }
    if (mLog.isDebugEnabled()) {
      mLog.debug("Starting TCP connector on port "
          + lPort + " with timeout "
          + (lTimeout > 0 ? lTimeout + "ms" : "infinite")
          + "");
    }
    ClientProcessor clientProc = new ClientProcessor(this);
    Thread clientThread = new Thread(clientProc);
    clientThread.start();
    if (mLog.isInfoEnabled()) {
      mLog.info("Started TCP connector on port "
          + lPort + " with timeout "
          + (lTimeout > 0 ? lTimeout + "ms" : "infinite")
          + "");
    }
  }

  @Override
  public void stopConnector(CloseReason aCloseReason) {
    if (mLog.isDebugEnabled()) {
      mLog.debug("Stopping TCP connector (" + aCloseReason.name() + ")...");
    }
    int lPort = mClientSocket.getPort();
    mCloseReason = aCloseReason;
    mIsRunning = false;

    try {
      mIn.close();
      if (mLog.isInfoEnabled()) {
        mLog.info("Stopped TCP connector ("
            + aCloseReason.name() + ") on port " + lPort + ".");
      }
    } catch (IOException ex) {
      if (mLog.isDebugEnabled()) {
        mLog.info(ex.getClass().getSimpleName() + " while stopping TCP connector ("
            + aCloseReason.name() + ") on port " + lPort + ": " + ex.getMessage());
      }
    }
  }

  @Override
  public void processPacket(WebSocketPacket aDataPacket) {
    // forward the data packet to the engine
    getEngine().processPacket(this, aDataPacket);
  }

  @Override
  public synchronized void sendPacket(WebSocketPacket aDataPacket) {
    try {
      if (aDataPacket.getFrameType() == RawPacket.FRAMETYPE_BINARY) {
        // each packet is enclosed in 0xFF<length><data>
        // TODO: for future use! Not yet finally spec'd in IETF drafts!
        mOut.write(0xFF);
        byte[] lBA = aDataPacket.getByteArray();
        // TODO: implement multi byte length!
        mOut.write(lBA.length);
        mOut.write(lBA);
      } else {
        // each packet is enclosed in 0x00<data>0xFF
        mOut.write(0x00);
        mOut.write(aDataPacket.getByteArray());
        mOut.write(0xFF);
      }
      mOut.flush();
    } catch (IOException ex) {
      mLog.error(ex.getClass().getSimpleName()
          + " sending data packet: " + ex.getMessage());
    }
  }

  private class ClientProcessor implements Runnable {

    private WebSocketConnector connector = null;

    /**
     * Creates the new socket listener thread for this connector.
     * @param aConnector
     */
    public ClientProcessor(WebSocketConnector aConnector) {
      connector = aConnector;
    }

    @Override
    public void run() {
      WebSocketEngine engine = getEngine();

      int lMaxFrameSize = JWebSocketCommonConstants.DEFAULT_MAX_FRAME_SIZE;
      EngineConfiguration config = engine.getConfiguration();
      if (config != null && config.getMaxFramesize() > 0) {
        lMaxFrameSize = config.getMaxFramesize();
      }
      byte[] lBuff = new byte[lMaxFrameSize];
      int pos = -1;
      int lStart = -1;

      try {
        // start client listener loop
        mIsRunning = true;

        // call connectorStarted method of engine
        engine.connectorStarted(connector);

        while (mIsRunning) {
          try {
            int b = mIn.read();
            // start of frame
            if (b == 0x00) {
              pos = 0;
              lStart = 0;
              // end of frame
            } else if (b == 0xff) {
              if (lStart >= 0) {
                if (pos <= lMaxFrameSize) {
                  RawPacket lPacket = new RawPacket(Arrays.copyOf(lBuff, pos));
                  try {
                    engine.processPacket(connector, lPacket);
                  } catch (Exception ex) {
                    mLog.error(ex.getClass().getSimpleName()
                        + " in processPacket of connector "
                        + connector.getClass().getSimpleName()
                        + ": " + ex.getMessage());
                  }
                } else {
                  mLog.error("Datapacket exceeded maximum size of " + lMaxFrameSize + " bytes and will not be processed!");
                }
              }
              lStart = -1;
              // end of stream
            } else if (b < 0) {
              mCloseReason = CloseReason.CLIENT;
              mIsRunning = false;
              // any other byte within or outside a frame
            } else {
              if (lStart >= 0 && pos < lMaxFrameSize) {
                lBuff[pos] = (byte) b;
              }
              pos++;
            }
          } catch (SocketTimeoutException ex) {
            mLog.error("(timeout) "
                + ex.getClass().getSimpleName()
                + ": " + ex.getMessage());
            mCloseReason = CloseReason.TIMEOUT;
            mIsRunning = false;
          } catch (Exception ex) {
            mLog.error("(other) "
                + ex.getClass().getSimpleName()
                + ": " + ex.getMessage());
            mCloseReason = CloseReason.SERVER;
            mIsRunning = false;
          }
        }

        // call client stopped method of engine
        // (e.g. to release client from streams)
        engine.connectorStopped(connector, mCloseReason);

        // br.close();
        mIn.close();
        mOut.close();
        mClientSocket.close();

      } catch (Exception ex) {
        // ignore this exception for now
        mLog.error("(close) "
            + ex.getClass().getSimpleName()
            + ": " + ex.getMessage());
      }
    }
  }

  @Override
  public String generateUID() {
    String lUID = mClientSocket.getInetAddress().getHostAddress()
        + "@" + mClientSocket.getPort();
    return lUID;
  }

  @Override
  public int getRemotePort() {
    return mClientSocket.getPort();
  }

  @Override
  public InetAddress getRemoteHost() {
    return mClientSocket.getInetAddress();
  }

  @Override
  public String toString() {
    // TODO: weird results like... '0:0:0:0:0:0:0:1:61130'... on JDK 1.6u19 Windows 7 64bit
    String lRes = getRemoteHost().getHostAddress() + ":" + getRemotePort();
    // TODO: don't hard code. At least use JWebSocketConstants field here.
    String lUsername = getString("org.jWebSocket.plugins.system.username");
    if (lUsername != null) {
      lRes += " (" + lUsername + ")";
    }
    return lRes;
  }
}
TOP

Related Classes of org.jwebsocket.tcp.connectors.TCPConnector$ClientProcessor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.