package com.walkertribe.ian.protocol.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;

/**
 * Respond to server discovery requests.
 * @author rjwut
 */
public class ServerDiscoveryResponder implements Runnable {
	static final int PORT = 3100;
	static final byte ACK = 0x06;

	private DatagramSocket skt;
	private boolean listening = false;
	private byte[] buffer = new byte[1];
	private byte[] response;

	public static void main(String[] args) throws IOException {
		final ServerDiscoveryResponder responder = new ServerDiscoveryResponder();
		new Thread(responder).start();
		ServerDiscoveryRequester.Listener listener = new ServerDiscoveryRequester.Listener() {
			@Override
			public void onDiscovered(Server server) {
				System.out.println("DISCOVERED: " + server);
			}

			@Override
			public void onStop() {
				System.out.println("Stopped");
				responder.stop();
			}
		};
		ServerDiscoveryRequester requester = new ServerDiscoveryRequester(listener, 5000);
		new Thread(requester).start();
	}

	/**
	 * Listen for server discovery requests, guessing the best PrivateNetworkAddress to use.
	 */
	public ServerDiscoveryResponder() throws IOException {
		this(PrivateNetworkAddress.guessBestPrivateNetworkAddress());
	}

	/**
	 * Listen for server discovery requests on the indicated PrivateNetworkAddress.
	 */
	public ServerDiscoveryResponder(PrivateNetworkAddress addr) throws IOException {
		if (addr == null) {
			throw new IllegalArgumentException("You must provide an address");
		}

		skt = new DatagramSocket(PORT);
		skt.setSoTimeout(1000);
		response = new Server(addr.getIp(), addr.getHostName()).toByteArray();
	}

	@Override
	public void run() {
		listening = true;

		try {
			while (listening) {
				DatagramPacket pkt = new DatagramPacket(buffer, buffer.length);

				try {
					skt.receive(pkt);
					InetAddress address = pkt.getAddress();
					int port = pkt.getPort();

					if (pkt.getData()[0] != ServerDiscoveryRequester.ENQ) {
						continue; // didn't get ENQ; ignore
					}

					DatagramPacket sendPacket = new DatagramPacket(response, response.length, address, port);
					skt.send(sendPacket);
				} catch (SocketTimeoutException ex) {
					// just drop into the next loop
				}
			}
		} catch (SocketException ex) {
			throw new RuntimeException(ex);
		} catch (IOException ex) {
			throw new RuntimeException(ex);
		} finally {
			if (skt != null) {
				skt.close();
			}
		}
	}

	/**
	 * Requests this object to stop listening for discovery requests.
	 */
	public void stop() {
		listening = false;
	}
}

@@ -555,91 +555,43 @@
 ;%0A%0A%09
-public static void main(String%5B%5D args) throws IOException %7B%0A%09%09final S
+/**%0A%09 * Listen for s
 erver
-D
+ d
 iscovery
 Resp
@@ -590,518 +590,189 @@
 very
-Responder responder = new ServerDiscoveryResponder();%0A%09%09new Thread(responder).start();%0A%09%09ServerDiscoveryRequester.Listener listener = new ServerDiscoveryRequester.Listener() %7B%0A%09%09%09@Override%0A%09%09%09public void onDiscovered(Server server) %7B%0A%09%09%09%09System.out.println(%22DISCOVERED: %22 + server);%0A%09%09%09%7D%0A%0A%09%09%09@Override%0A%09%09%09public void onStop() %7B%0A%09%09%09%09System.out.println(%22Stopped%22);%0A%09%09%09%09responder.stop();%0A%09%09%09%7D%0A%09%09%7D;%0A%09%09ServerDiscoveryRequester requester = new ServerDiscoveryRequester(listener, 5000);%0A%09%09new Thread(requester).start(
+ requests, guessing the best PrivateNetworkAddress to use.%0A%09 */%0A%09public ServerDiscoveryResponder() throws IOException %7B%0A%09%09init(PrivateNetworkAddress.guessBestPrivateNetworkAddress()
 );%0A%09
@@ -817,37 +817,38 @@
 y requests, 
-guess
+report
 ing the 
 best Private
@@ -839,40 +839,29 @@
 the 
-best PrivateNetworkAddress to us
+given IP and host nam
 e.%0A%09
@@ -901,135 +901,123 @@
 der(
-) throws IOException %7B%0A%09%09this(PrivateNetworkAddress.guessBestPrivateNetworkAddress());%0A%09%7D%0A%0A%09/**%0A%09 * Listen for s
+String ip, String hostName) throws IOException %7B%0A%09%09init(ip, hostName);%0A%09%7D%0A%0A%09/**%0A%09 * Initializes the S
 erver
- d
+D
 iscovery
  req
@@ -1016,34 +1016,33 @@
 very
- requests on the indicated
+Responder using the given
  Pri
@@ -1072,38 +1072,24 @@
 /%0A%09p
-ublic ServerDiscoveryResponder
+rivate void init
 (Pri
@@ -1174,69 +1174,267 @@
 ew I
-llegalArgumentException(%22You must provide an address%22
+OException(%22No suitable network interface found%22);%0A%09%09%7D%0A%0A%09%09init(addr.getIp(), addr.getHostName()
 );%0A
-%09
 %09%7D%0A%0A
+%09/**%0A%09 * Initializes the ServerDiscoveryResponder using the given IP and host name.%0A%09 */%0A%09private void init(String ip, String hostName) throws IOException %7B%0A
 %09%09sk
@@ -1517,40 +1517,20 @@
 ver(
-addr.getIp(), addr.getH
+ip, h
 ostName
-()
 ).to

Remove main(), allow user to specify IP and hostname