//
// MUConnection.java
// Thud
//
// Created by asp on Fri Nov 16 2001.
// Copyright (c) 2001-2007 Anthony Parker & the THUD team.
// All rights reserved. See LICENSE.TXT for more information.
//
package net.sourceforge.btthud.engine;
import net.sourceforge.btthud.engine.commands.Command;
import net.sourceforge.btthud.ui.Thud;
import net.sourceforge.btthud.data.MUHost;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
/**
* This class is for handling the basic connection between the HUD and the MUX.
* It offers limited support for TELNET (RFC 854), mostly for the purpose of
* ignoring TELNET option negotiation.
*
* TODO: Implement the RFC 854 support.
*
* @author Anthony Parker
*/
public class MUConnection implements Runnable {
public boolean connected = false;
private final Socket conn;
private final BufferedInputStream in;
private final BufferedOutputStream out;
private Thud errorHandler = null;
private BufferedReader rd;
private BufferedWriter wr;
private Thread connThread = null;
private boolean go = true;
private MUParse parse = null;
/**
* Creates a new MUConnection object, connects to the host, and starts
* recieving data and storing it.
*
* @param host The IP address or name of the host we're connecting to.
* @param port The port of the host we're connecting to.
* @see check
* @see endConnection
*/
public MUConnection (final MUHost host, Thud errorHandler,
final MUParse parse)
throws UnknownHostException, IOException {
this.errorHandler = errorHandler;
this.parse = parse;
conn = new Socket (host.getHost(), host.getPort());
in = new BufferedInputStream (conn.getInputStream());
out = new BufferedOutputStream (conn.getOutputStream());
rd = new BufferedReader (new InputStreamReader (in, "US-ASCII"));
wr = new BufferedWriter (new OutputStreamWriter (out, "US-ASCII"));
this.connected = true;
start();
}
/**
* Start the MUConnection thread.
*/
public void start () {
if (connThread == null) {
connThread = new Thread (this, "MUConnection");
connThread.start();
}
}
/**
* Write line to output.
*
* @param command The string which holds the command we want to run.
*/
public void sendCommand (final Command command) throws IOException {
if (command.isEmpty())
return;
sendLine(command.toString());
}
private void sendLine (String command) throws IOException {
try {
wr.write(command);
wr.write("\r\n");
wr.flush();
} catch (SocketException e) {
// If we get a socket exception - disconnect.
// This is kinda hacked up - ideally the thread
// communication would work a little better.
// But, it prevents a bug where if the remote
// connection is closed, THUD goes to 100% cpu and
// throws SocketExceptions all the livelong day :)
System.err.println("Lost connection - aborting");
errorHandler.doStop();
errorHandler.stopConnection();
} catch (Exception e) {
System.err.println("Error: " + e);
}
}
/**
* Reads lines from input.
*/
public void run () {
while (go) {
try {
// TODO: readLine() isn't smart enough, because
// we need to parse TELNET sequences (IACs) at
// the byte stream level.
//
// It also might be appropriate to parse ANSI
// escapes at the byte stream level, but we're
// probably OK on that count, since ANSI
// sequences are all encoded within the bounds
// of the US-ASCII charset.
parse.parseLine(rd.readLine());
} catch (IOException e) {
errorHandler.stopConnection();
} catch (Exception e) {
System.err.println("Error: connection: " + e);
}
}
}
public void pleaseStop () {
try {
conn.close(); // close the socket
this.connected = false;
} catch (Exception e) {
System.err.println("Error: closeSocket: " + e);
}
go = false;
}
}