package mediabrowser.apiinteraction.discovery;
import mediabrowser.apiinteraction.Response;
import mediabrowser.model.apiclient.ServerDiscoveryInfo;
import mediabrowser.model.logging.ILogger;
import mediabrowser.model.serialization.IJsonSerializer;
import java.io.IOException;
import java.net.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
public class ServerLocator implements IServerLocator {
private ILogger logger;
private IJsonSerializer jsonSerializer;
public ServerLocator(ILogger logger, IJsonSerializer jsonSerializer) {
this.logger = logger;
this.jsonSerializer = jsonSerializer;
}
@Override
public void FindServers(int timeoutMs, Response<ArrayList<ServerDiscoveryInfo>> response)
{
// Find the server using UDP broadcast
try {
//Open a random port to send the package
DatagramSocket c = new DatagramSocket();
c.setBroadcast(true);
byte[] sendData = "who is EmbyServer?".getBytes();
int port = 7359;
//Try the 255.255.255.255 first
try {
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getByName("255.255.255.255"), port);
c.send(sendPacket);
logger.Debug(getClass().getName() + ">>> Request packet sent to: 255.255.255.255 (DEFAULT)");
} catch (Exception e) {
logger.ErrorException("Error sending DatagramPacket", e);
}
// Broadcast the message over all the network interfaces
Enumeration interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface networkInterface = (NetworkInterface)interfaces.nextElement();
if (networkInterface.isLoopback() || !networkInterface.isUp()) {
continue; // Don't want to broadcast to the loopback interface
}
for (InterfaceAddress interfaceAddress : networkInterface.getInterfaceAddresses()) {
InetAddress broadcast = interfaceAddress.getBroadcast();
if (broadcast == null) {
continue;
}
// Send the broadcast package!
try {
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, broadcast, port);
c.send(sendPacket);
} catch (Exception e) {
logger.ErrorException("Error sending DatagramPacket", e);
}
logger.Debug(getClass().getName() + ">>> Request packet sent to: " + broadcast.getHostAddress() + "; Interface: " + networkInterface.getDisplayName());
}
}
logger.Debug(getClass().getName() + ">>> Done looping over all network interfaces. Now waiting for a reply!");
Receive(c, timeoutMs, response);
//Close the port!
c.close();
} catch (Exception ex) {
logger.ErrorException("Error finding servers", ex);
response.onError(ex);
}
}
private void Receive(DatagramSocket c, long timeoutMs, Response<ArrayList<ServerDiscoveryInfo>> response) throws IOException {
ArrayList<ServerDiscoveryInfo> servers = new ArrayList<ServerDiscoveryInfo>();
ArrayList<String> foundServerIds = new ArrayList<String>();
while (timeoutMs > 0){
long startTime = System.currentTimeMillis();
// Wait for a response
byte[] recvBuf = new byte[15000];
DatagramPacket receivePacket = new DatagramPacket(recvBuf, recvBuf.length);
c.setSoTimeout((int)timeoutMs);
try {
c.receive(receivePacket);
}
catch (SocketTimeoutException e) {
logger.Debug("Server discovery timed out waiting for response.");
break;
}
SocketAddress remoteEndpoint = c.getRemoteSocketAddress();
// We have a response
logger.Debug(getClass().getName() + ">>> Broadcast response from server: " + receivePacket.getAddress().getHostAddress());
// Check if the message is correct
String message = new String(receivePacket.getData()).trim();
logger.Debug(getClass().getName() + ">>> Broadcast response from server: " + message);
ServerDiscoveryInfo serverInfo = jsonSerializer.DeserializeFromString(message, ServerDiscoveryInfo.class);
if (remoteEndpoint != null){
serverInfo.setEndpointAddress(remoteEndpoint.toString());
}
if (foundServerIds.indexOf(serverInfo.getId()) == -1){
foundServerIds.add(serverInfo.getId());
servers.add(serverInfo);
}
long endTime = System.currentTimeMillis();
timeoutMs = timeoutMs - (endTime - startTime);
}
logger.Debug("Found %d servers", servers.size());
response.onResponse(servers);
}
}