336 lines
12 KiB
Java
336 lines
12 KiB
Java
|
|
import java.io.*;
|
|
import java.net.*;
|
|
import java.util.*;
|
|
|
|
public class KaZaServer implements Runnable
|
|
{
|
|
public static final int LISTEN_PORT = 3442;
|
|
private ServerSocket m_serverSocket;
|
|
private HashMap<String, ClientInfo> m_clientData;
|
|
private Vector<Socket> m_peerGroupLeaders;
|
|
private HashMap<String, Integer> m_currentSearches;
|
|
|
|
public KaZaServer()
|
|
{
|
|
m_clientData = new HashMap<String, ClientInfo>();
|
|
m_peerGroupLeaders = new Vector<Socket>();
|
|
m_currentSearches = new HashMap<String, Integer>();
|
|
}
|
|
|
|
public void run()
|
|
{
|
|
try {
|
|
m_serverSocket = new ServerSocket(LISTEN_PORT);
|
|
|
|
/* porcess connection requests */
|
|
for (;;)
|
|
{
|
|
Socket clientSocket = m_serverSocket.accept();
|
|
|
|
Thread thread = new Thread(new ClientHandler(clientSocket));
|
|
thread.start();
|
|
}
|
|
} catch (IOException ioe) {
|
|
System.out.println("KaZaServer: IO Exception!");
|
|
ioe.printStackTrace();
|
|
return;
|
|
}
|
|
}
|
|
|
|
public void connectToPeerGroupLeader(String peerName,
|
|
boolean sendReverseConnectMsg)
|
|
{
|
|
/* check if the peer group leader is already in our list */
|
|
synchronized (m_peerGroupLeaders)
|
|
{
|
|
for (Socket s : m_peerGroupLeaders)
|
|
{
|
|
if (s.getInetAddress().getHostAddress().equals(peerName))
|
|
return;
|
|
}
|
|
}
|
|
|
|
Socket s;
|
|
try
|
|
{
|
|
s = new Socket(peerName, LISTEN_PORT);
|
|
DataOutputStream os = new DataOutputStream(s.getOutputStream());
|
|
os.writeBytes("HELO KaZaServer\n");
|
|
if (sendReverseConnectMsg)
|
|
os.writeBytes("GRPL\n");
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* add new peer group leader to the peer group leaders list */
|
|
synchronized (m_peerGroupLeaders)
|
|
{
|
|
m_peerGroupLeaders.add(s);
|
|
}
|
|
}
|
|
|
|
public void close()
|
|
{
|
|
}
|
|
|
|
public Object[] getClientList()
|
|
{
|
|
Set<String> s;
|
|
synchronized (m_clientData)
|
|
{
|
|
s = m_clientData.keySet();
|
|
}
|
|
return s.toArray();
|
|
}
|
|
|
|
public Object[] getPeerGroupLeaderList()
|
|
{
|
|
Vector<String> peers = new Vector<String>();
|
|
synchronized (m_peerGroupLeaders)
|
|
{
|
|
for (Socket s : m_peerGroupLeaders)
|
|
{
|
|
peers.add(s.getInetAddress().getHostAddress());
|
|
}
|
|
}
|
|
return peers.toArray();
|
|
}
|
|
|
|
private class ClientInfo
|
|
{
|
|
String userName = "Anonymous";
|
|
int speed = 1500;
|
|
HashMap<String, String> files = new HashMap<String, String>();
|
|
}
|
|
|
|
private class ClientHandler implements Runnable
|
|
{
|
|
private Socket m_socket;
|
|
private String m_clientIP;
|
|
ClientInfo m_clientInfo;
|
|
|
|
public ClientHandler(Socket socket)
|
|
{
|
|
m_socket = socket;
|
|
m_clientIP = m_socket.getInetAddress().getHostAddress();
|
|
synchronized (m_clientData)
|
|
{
|
|
if (!m_clientData.containsKey(m_clientIP))
|
|
{
|
|
m_clientData.put(socket.getInetAddress().getHostAddress(),
|
|
new ClientInfo());
|
|
}
|
|
m_clientInfo = m_clientData.get(m_clientIP);
|
|
}
|
|
}
|
|
|
|
public void run()
|
|
{
|
|
try
|
|
{
|
|
BufferedReader br = new BufferedReader(
|
|
new InputStreamReader(
|
|
m_socket.getInputStream()));
|
|
DataOutputStream os = new DataOutputStream(
|
|
m_socket.getOutputStream());
|
|
|
|
/* loop processing client messages */
|
|
boolean running = true;
|
|
while (running)
|
|
{
|
|
String inLine = br.readLine();
|
|
|
|
StringTokenizer tokens = new StringTokenizer(inLine);
|
|
if (!tokens.hasMoreTokens())
|
|
continue;
|
|
|
|
String opCode = tokens.nextToken();
|
|
opCode = opCode.toUpperCase();
|
|
if (opCode.equals("HELO"))
|
|
{
|
|
/* user is announcing his or her username */
|
|
synchronized (m_clientData)
|
|
{
|
|
m_clientInfo.userName = inLine.substring(5);
|
|
}
|
|
// System.out.println("Got HELO from " + m_clientInfo.userName);
|
|
}
|
|
else if (opCode.equals("SPED"))
|
|
{
|
|
/* user is telling us their connection speed */
|
|
if (tokens.hasMoreTokens())
|
|
{
|
|
int speed = Integer.parseInt(tokens.nextToken());
|
|
synchronized (m_clientData)
|
|
{
|
|
m_clientInfo.speed = speed;
|
|
}
|
|
// System.out.println("Got SPED of " + m_clientInfo.speed);
|
|
}
|
|
}
|
|
else if (opCode.equals("DESC"))
|
|
{
|
|
/* user is giving us a description of a file */
|
|
String fileName = inLine.substring(5);
|
|
String fileDesc = br.readLine();
|
|
synchronized (m_clientData)
|
|
{
|
|
m_clientInfo.files.put(fileName, fileDesc);
|
|
}
|
|
// System.out.println("Got DESC of '" + fileName +
|
|
// "': '" + fileDesc + "'");
|
|
}
|
|
else if (opCode.equals("SRCH"))
|
|
{
|
|
/* user is requesting a search */
|
|
if (tokens.hasMoreTokens())
|
|
{
|
|
int depth = Integer.parseInt(tokens.nextToken());
|
|
if (tokens.hasMoreTokens())
|
|
{
|
|
String query = tokens.nextToken();
|
|
String searchResults = performSearch(depth, query, m_socket);
|
|
os.writeBytes(searchResults);
|
|
os.writeBytes(".\n");
|
|
// System.out.println("Got SRCH for " + query +
|
|
// ", results:\n" + searchResults);
|
|
}
|
|
}
|
|
}
|
|
else if (opCode.equals("QUIT"))
|
|
{
|
|
/* user is requesting to leave the system */
|
|
br.close();
|
|
os.close();
|
|
m_socket.close();
|
|
running = false;
|
|
}
|
|
else if (opCode.equals("GRPL"))
|
|
{
|
|
/* user is a peer group leader, initiate a connection
|
|
* to it if one is not established */
|
|
connectToPeerGroupLeader(m_clientIP, false);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception e) { }
|
|
finally
|
|
{
|
|
synchronized (m_clientData)
|
|
{
|
|
m_clientData.remove(m_clientIP);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private String performSearch(int depth, String query, Socket clientSocket)
|
|
{
|
|
String results = "";
|
|
String querylc = query.toLowerCase();
|
|
|
|
/* don't perform a search that we are already performing
|
|
* (avoid duplicate results */
|
|
synchronized (m_currentSearches)
|
|
{
|
|
if (m_currentSearches.containsKey(querylc))
|
|
return results;
|
|
m_currentSearches.put(querylc, 1);
|
|
}
|
|
|
|
if (depth > 0)
|
|
{
|
|
synchronized (m_peerGroupLeaders)
|
|
{
|
|
for (int i = 0; i < m_peerGroupLeaders.size(); i++)
|
|
{
|
|
if (m_peerGroupLeaders.elementAt(i).isClosed())
|
|
{
|
|
m_peerGroupLeaders.removeElementAt(i);
|
|
i--;
|
|
}
|
|
else
|
|
{
|
|
String peerResults =
|
|
getSearchResultsFromPeerGroupLeader(
|
|
m_peerGroupLeaders.elementAt(i),
|
|
depth-1, query);
|
|
results += peerResults;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* now search my own file list */
|
|
synchronized (m_clientData)
|
|
{
|
|
Set<String> clients = m_clientData.keySet();
|
|
for (String clientIP : clients)
|
|
{
|
|
HashMap<String, String> files = m_clientData.get(clientIP).files;
|
|
Set<String> clientFiles = files.keySet();
|
|
for (String fileName : clientFiles)
|
|
{
|
|
String fnamelc = fileName.toLowerCase();
|
|
if ( (fnamelc.indexOf(querylc) >= 0) ||
|
|
(files.get(fileName).toLowerCase().indexOf(querylc) >= 0) )
|
|
{
|
|
/* clientIPToReturn will hold our MNH server's opinion
|
|
* of the client IP address which has the file being
|
|
* searched for *unless* it starts with "127.", in which
|
|
* case it is a local connection and the client performing
|
|
* the search should receive back whichever IP it is using
|
|
* to talk to the MNH server */
|
|
String clientIPToReturn =
|
|
clientIP.startsWith("127.")
|
|
? clientSocket.getLocalAddress().getHostAddress()
|
|
: clientIP;
|
|
results += clientIPToReturn + "|" +
|
|
m_clientData.get(clientIP).userName + "|" +
|
|
m_clientData.get(clientIP).speed + "|" +
|
|
fileName + "|" +
|
|
files.get(fileName) + "\n";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
synchronized (m_currentSearches)
|
|
{
|
|
m_currentSearches.remove(querylc);
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
private String getSearchResultsFromPeerGroupLeader(Socket s, int depth,
|
|
String query)
|
|
{
|
|
String searchResults = "";
|
|
try
|
|
{
|
|
BufferedReader br = new BufferedReader(
|
|
new InputStreamReader(
|
|
s.getInputStream()));
|
|
DataOutputStream os = new DataOutputStream(s.getOutputStream());
|
|
|
|
os.writeBytes("SRCH " + depth + " " + query + "\n");
|
|
for (;;)
|
|
{
|
|
String inLine = br.readLine();
|
|
if (inLine.equals("."))
|
|
break;
|
|
searchResults += inLine + "\n";
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
return "";
|
|
}
|
|
return searchResults;
|
|
}
|
|
}
|