import java.io.*;
import java.net.*;
import java.util.concurrent.*;
import java.util.ArrayList;
import lejos.pc.comm.NXTCommException;
/* Send command -1 to cleanly shutdown server, closing bluetooth connection */
public class Server {
protected boolean loopback = false;
private PCBluetooth pcb = null;
private int port = 6879;
private ServerSocket ss = null;
private boolean finished = false;
private ArrayList<Socket> sockets = new ArrayList<Socket>();
private ExecutorService executor = null;
private boolean commandSent = false;
protected boolean restart = false;
public static void main(String[] args) throws NXTCommException{
Server server = new Server();
if (args.length > 0){
server.loopback = true;
}
do{
server.restart = false;
server.startServer();
}while(server.restart);
}
private void reconnect(){
if (!loopback){
boolean reconnect = true;
while(reconnect){
try{
pcb.openConnection();
System.out.println("connected!");
reconnect = false;
}catch(NXTCommException e){
System.err.println("failed to connect. retrying in 3 seconds.");
reconnect = true;
try{
Thread.sleep(3000);
}catch(InterruptedException ee){
// meh
}
pcb = new PCBluetooth();
}
}
}
}
public void startServer() throws NXTCommException {
pcb = new PCBluetooth();
reconnect();
try{
ss = new ServerSocket(port);
if (loopback)
System.out.println("=== Loopback mode ===");
System.out.println( "Server started on port " +
port + ", waiting for connection." );
serverLoop();
}catch(IOException e){
System.err.println("Could not open ServerSocket, or was interrupted.");
}
if(loopback){
System.out.println("Exiting safely in loopback mode.");
return;
}
try{
pcb.closeConnection();
System.out.println("Connection to robot closed.");
}catch(IOException e){
System.err.println("Could not close connection to robot.");
}
}
public synchronized void sendMessage(int message) throws IOException {
commandSent = true;
if (loopback)
return;
pcb.sendMessage(message);
}
public void serverLoop() throws IOException{
executor = Executors.newCachedThreadPool();
executor.execute(new ConnectionListener());
executor.execute(new KeepAlive());
if(!loopback){executor.execute(new BTListener());}
while(!finished){
if(restart){
reconnect();
restart = false;
}
try{
Thread.sleep(250);
}catch(InterruptedException e){
// don't care
}
}
ss.close();
for(Socket s: sockets){
s.close();
}
executor.shutdownNow();
}
class BTListener implements Runnable {
public void run(){
while(!finished){
try{
int message = pcb.readMessage();
for(Socket s: sockets){
try{
OutputStream os = s.getOutputStream(); // lazy
os.write(message); // try/catch this?
}catch(IOException e){
// probably dead connection, ignore
}
}
}catch(IOException e){
// disregard, carry on
}
}
}
}
class KeepAlive implements Runnable {
public void run(){
while(!finished){
commandSent = false;
try{
Thread.sleep(5000);
}catch(InterruptedException e){
// nobody cares
}
if(!commandSent){
try{
sendMessage(0);
}catch(IOException e){
restart = true;
}
}
}
}
}
class ConnectionListener implements Runnable{
public void run(){
try{
while(true){
Socket socket = ss.accept();
sockets.add(socket);
executor.execute(new ConnectionHandler(socket));
}
}catch(IOException e){
finished = true;
System.err.println("ServerSocket IO error");
}
}
}
class ConnectionHandler implements Runnable {
private Socket socket = null;
ConnectionHandler(Socket socket){
this.socket = socket;
}
public void run(){
try{
System.out.println( "New connection from: " +
socket.getInetAddress().toString() );
InputStream is = socket.getInputStream();
String num = "";
int i;
char c;
while((i = is.read()) != -1){
c = (char) i;
if (c == '\n') {
try{
int z = Integer.parseInt(num);
if(z == -1){
restart = false;
break;
}
try{
sendMessage(z);
System.out.println(socket.getInetAddress().toString() + ": " + z);
}catch(IOException e){
restart = true;
}
}catch(NumberFormatException e){
System.err.println("invalid message found?");
}
num = "";
} else { // c != '\n'
num += new Character(c).toString();
}
}
is.close();
socket.close();
System.out.println( "Connection closed: " +
socket.getInetAddress().toString() );
}catch(IOException e){
System.err.println( "Lost connection to client: " +
socket.getInetAddress().toString() );
}
}
}
}