summaryrefslogtreecommitdiffstats
path: root/libraries/oscP5/src/netP5/AbstractTcpClient.java
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/oscP5/src/netP5/AbstractTcpClient.java')
-rw-r--r--libraries/oscP5/src/netP5/AbstractTcpClient.java491
1 files changed, 491 insertions, 0 deletions
diff --git a/libraries/oscP5/src/netP5/AbstractTcpClient.java b/libraries/oscP5/src/netP5/AbstractTcpClient.java
new file mode 100644
index 0000000..7f6cac4
--- /dev/null
+++ b/libraries/oscP5/src/netP5/AbstractTcpClient.java
@@ -0,0 +1,491 @@
+/**
+ * A network library for processing which supports UDP, TCP and Multicast.
+ *
+ * (c) 2004-2012
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307 USA
+ *
+ * @author Andreas Schlegel http://www.sojamo.de
+ * @modified 12/23/2012
+ * @version 0.9.9
+ */
+
+package netP5;
+
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.net.Socket;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+
+/**
+ * @invisible
+ */
+public abstract class AbstractTcpClient implements Runnable {
+
+ private Socket _mySocket;
+
+ protected TcpPacketListener _myTcpPacketListener;
+
+ private PrintWriter _myOutput = null;
+
+ private BufferedReader _myInput = null;
+
+ private OutputStream _myOutputStream = null;
+
+ protected byte[] _myBytes = new byte[0];
+
+ protected StringBuffer _myStringBuffer = new StringBuffer(0);
+
+ protected AbstractTcpServer _myTcpServer;
+
+ protected NetAddress _myNetAddress;
+
+ protected int _myServerPort;
+
+ private Thread _myThread;
+
+ private char TERMINATOR = '\0';
+
+ /**
+ * terminator is readline.
+ */
+ public static final int MODE_READLINE = 0;
+
+ /**
+ * terminator is terminated, by default this is character '\0'
+ * and can be set with setTerminator
+ */
+ public static final int MODE_TERMINATED = 1;
+
+ /**
+ * terminator is newline.
+ */
+ public static final int MODE_NEWLINE = 2;
+
+ /**
+ * no terminator required, packets are sent via
+ * a tcp stream.
+ */
+ public static final int MODE_STREAM = 3;
+
+ private final int _myMode;
+
+ /**
+ * @invisible
+ * @param theTcpPacketListener TcpPacketListener
+ * @param theHost String
+ * @param thePort int
+ */
+ public AbstractTcpClient(final TcpPacketListener theTcpPacketListener,
+ final String theHost,
+ final int thePort) {
+ this(theTcpPacketListener, theHost, thePort, MODE_READLINE);
+ }
+
+ /**
+ * @invisible
+ * @param theHost String
+ * @param thePort int
+ */
+ public AbstractTcpClient(final String theHost,
+ final int thePort) {
+ this(null, theHost, thePort, MODE_READLINE);
+ }
+
+ /**
+ * @invisible
+ * @param theTcpPacketListener TcpPacketListener
+ * @param theHost String
+ * @param thePort int
+ * @param theMode int
+ */
+ public AbstractTcpClient(final TcpPacketListener theTcpPacketListener,
+ final String theHost,
+ final int thePort,
+ final int theMode) {
+ _myTcpPacketListener = theTcpPacketListener;
+ _myNetAddress = new NetAddress(theHost, thePort);
+ _myMode = theMode;
+ startSocket();
+ }
+
+ /**
+ * @invisible
+ * @param theHost String
+ * @param thePort int
+ * @param theMode int
+ */
+ public AbstractTcpClient(final String theHost,
+ final int thePort,
+ final int theMode) {
+ this(null, theHost, thePort, theMode);
+ }
+
+
+ /**
+ * @invisible
+ * @param theTcpServer AbstractTcpServer
+ * @param theSocket Socket
+ * @param theTcpPacketListener TcpPacketListener
+ * @param theServerPort int
+ * @param theMode int
+ */
+ public AbstractTcpClient(final AbstractTcpServer theTcpServer,
+ final Socket theSocket,
+ final TcpPacketListener theTcpPacketListener,
+ final int theServerPort,
+ final int theMode) {
+ _myTcpServer = theTcpServer;
+ _mySocket = theSocket;
+ _myTcpPacketListener = theTcpPacketListener;
+ _myServerPort = theServerPort;
+ _myMode = theMode;
+ startSocket();
+ }
+
+
+ private void startSocket() {
+ try {
+ if (_mySocket == null) {
+ _mySocket = new Socket(_myNetAddress.address(), _myNetAddress.port());
+ } else {
+ _myNetAddress = new NetAddress(_mySocket.getInetAddress().getHostAddress(),
+ _mySocket.getPort());
+ }
+ Logger.printProcess("TcpClient", "### starting new TcpClient " + _myNetAddress);
+ if (_myMode == MODE_STREAM) {
+ _myOutputStream = _mySocket.getOutputStream();
+ }
+ init();
+ } catch (final IOException e) {
+ Logger.printError("TcpClient",
+ "IOException while trying to create a new socket.");
+// handleStatus(NetStatus.CONNECTION_FAILED); // FIX! NetPlug is still null at this point. NetPlug has to exist first.
+ }
+ }
+
+
+ /**
+ * when a TCP connection is lost, reconnect to the server with reconnect().
+ */
+ public void reconnect() {
+ try {
+ Thread.sleep(1000);
+ } catch(final Exception e) { }
+ startSocket();
+ }
+
+
+ private void init() {
+ _myThread = new Thread(this);
+ _myThread.start();
+ }
+
+ /**
+ * to parse an incomming tcp message, a terminator character is required to
+ * determine the end of the message so that it can be parsed and forwarded.
+ *
+ * @param theTerminator
+ */
+ public void setTerminator(final char theTerminator) {
+ TERMINATOR = theTerminator;
+ }
+
+ /**
+ * stop and dispose a tcp client.
+ */
+ public void dispose() {
+ try {
+ // do io streams need to be closed first?
+ if (_myInput != null) {
+ _myInput.close();
+ }
+ if (_myOutput != null) {
+ _myOutput.close();
+ }
+
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+ _myInput = null;
+ _myOutput = null;
+
+ try {
+ if (_mySocket != null) {
+ _mySocket.close();
+ }
+
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+ if(_myThread==null) {
+ return;
+ }
+ _mySocket = null;
+ _myThread = null;
+ handleStatus(NetStatus.CONNECTION_CLOSED);
+ Logger.printProcess("TcpClient.dispose", "TcpClient closed.");
+ }
+
+ /**
+ * @invisible
+ */
+ public void run() {
+ if (_myMode == MODE_STREAM) {
+ try {
+ try {
+ // sleep a little bit to avoid threading and nullpointer
+ // issues when reconnecting.
+ _myThread.sleep(500);
+ } catch (final Exception e) {
+
+ }
+
+ final InputStream in = _mySocket.getInputStream();
+ while (!_mySocket.isClosed() && _mySocket != null) {
+ final int myLen = Bytes.toIntBigEndian(in);
+ if (myLen < 0) {
+ break;
+ }
+ _myBytes = Bytes.toByteArray(in, myLen);
+ handleInput();
+ }
+ } catch (final java.net.SocketException se) {
+ System.out.println("Connection reset.");
+ } catch (final Exception e) {
+ System.out.println("### EXCEPTION " + e);
+ }
+ try {
+ handleStatus(NetStatus.SERVER_CLOSED);
+ handleStatus(NetStatus.CONNECTION_TERMINATED);
+ dispose();
+ } catch (final NullPointerException e) {
+ System.out.println("### nullpointer while calling handleStatus.");
+ }
+ } else {
+ while (Thread.currentThread() == _myThread) {
+ switch (_myMode) {
+ case (MODE_TERMINATED):
+ read();
+ break;
+ case (MODE_READLINE):
+ default:
+ readline();
+ break;
+ }
+ break;
+ }
+ }
+ if (_myTcpServer != null) {
+ _mySocket = null;
+ _myTcpServer.remove(this);
+ }
+ }
+
+
+ private void read() {
+ try {
+ _myInput = new BufferedReader(new InputStreamReader(_mySocket.getInputStream()));
+
+ final char[] charBuffer = new char[1];
+ while (_myInput.read(charBuffer, 0, 1) != -1) {
+
+ /**@todo
+ * StringBuffer size is limited yet.
+ * increase the buffer size dynamically.
+ */
+ _myStringBuffer = new StringBuffer(4096);
+ while (charBuffer[0] != TERMINATOR && charBuffer[0] != 3) {
+ _myStringBuffer.append(charBuffer[0]);
+ _myInput.read(charBuffer, 0, 1);
+ }
+ _myBytes = _myStringBuffer.toString().getBytes();
+ handleInput();
+ }
+ } catch (final IOException e) {
+ Logger.printProcess("TcpClient.read()", "connection has been terminated.");
+ if (_myTcpServer == null) {
+ handleStatus(NetStatus.SERVER_CLOSED);
+ }
+ handleStatus(NetStatus.CONNECTION_TERMINATED);
+ }
+ }
+
+
+ private void readline() {
+ try {
+ _myOutput = new PrintWriter(_mySocket.getOutputStream(), true);
+ _myInput = new BufferedReader(new InputStreamReader(_mySocket.getInputStream()));
+ String inputLine;
+
+ while ((inputLine = _myInput.readLine()) != null) {
+ _myStringBuffer = new StringBuffer(inputLine);
+ _myBytes = _myStringBuffer.toString().getBytes();
+ handleInput();
+ }
+ } catch (final IOException e) {
+ Logger.printProcess("TcpClient.readline()", "connection has been terminated.");
+ handleStatus(NetStatus.CONNECTION_TERMINATED);
+ if (_myTcpServer == null) {
+ handleStatus(NetStatus.SERVER_CLOSED);
+ }
+ }
+ }
+
+ /**
+ * @invisible
+ */
+ public abstract void handleInput();
+
+ /**
+ * @invisible
+ * @param theIndex
+ */
+ public abstract void handleStatus(int theIndex);
+
+ /**
+ * @invisible
+ * @return
+ */
+ public TcpPacketListener listener() {
+ return _myTcpPacketListener;
+ }
+
+ /**
+ * get the server port.
+ * @return
+ */
+ public int serverport() {
+ return _myServerPort;
+ }
+
+ /**
+ * get the instance of the socket. more info at java.net.Socket
+ * @return
+ */
+ public Socket socket() {
+ return _mySocket;
+ }
+
+
+ /**
+ * get the mode of the terminator.
+ * @return
+ */
+ public int mode() {
+ return _myMode;
+ }
+
+
+ public String getString() {
+ return _myStringBuffer.toString();
+ }
+
+
+ public StringBuffer getStringBuffer() {
+ return _myStringBuffer;
+ }
+
+
+ public void send(final byte[] theBytes) {
+ if (_myMode == MODE_STREAM) {
+ try {
+ Bytes.toStream(_myOutputStream, theBytes);
+ } catch (final Exception ex) {
+ handleStatus(NetStatus.SEND_FAILED);
+ }
+ } else {
+ System.out.println("### sending bytes is only supported for STREAMs");
+ }
+ }
+
+
+ public void send(final byte[][] theBytes) {
+ if (_myMode == MODE_STREAM) {
+ try {
+ for (int i = 0; i < theBytes.length; i++) {
+ Bytes.toStream(_myOutputStream, theBytes[i]);
+ }
+ } catch (final Exception ex) {
+ handleStatus(NetStatus.SEND_FAILED);
+ }
+ } else {
+ System.out.println("### sending bytes is only supported for STREAMs");
+ }
+
+ }
+
+
+ public void send(final String theString) {
+ if (_myMode == MODE_STREAM) {
+ send(theString.getBytes());
+ } else {
+ switch (_myMode) {
+ case (MODE_TERMINATED):
+ _myOutput.write(theString + TERMINATOR);
+ break;
+ case (MODE_NEWLINE):
+ _myOutput.write(theString + "\n");
+ break;
+ case (MODE_READLINE):
+ default:
+ _myOutput.println(theString);
+ break;
+ }
+ _myOutput.flush();
+ }
+ }
+
+
+ public NetAddress netAddress() {
+ return _myNetAddress;
+ }
+
+
+ /**
+ * @deprecated
+ * @invisible
+ * @return NetAddress
+ */
+
+ public NetAddress netaddress() {
+ return _myNetAddress;
+ }
+
+
+ /**
+ * @param theNetAddress NetAddress
+ * @return boolean
+ */
+ public boolean equals(final NetAddress theNetAddress) {
+ if (theNetAddress.address().equals(_myNetAddress.address()) &&
+ theNetAddress.port() == _myNetAddress.port()) {
+ return true;
+ }
+ return false;
+ }
+
+
+ public boolean equals(final TcpClient theClient) {
+ return equals(theClient.netAddress());
+ }
+
+}