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 m_clientData; private Vector m_peerGroupLeaders; private HashMap m_currentSearches; public KaZaServer() { m_clientData = new HashMap(); m_peerGroupLeaders = new Vector(); m_currentSearches = new HashMap(); } 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) { Socket s; try { s = new Socket(peerName, LISTEN_PORT); DataOutputStream os = new DataOutputStream(s.getOutputStream()); os.writeBytes("HELO KaZaServer\n"); } catch (Exception e) { return; } synchronized (m_peerGroupLeaders) { m_peerGroupLeaders.add(s); } } public void close() { } public Object[] getClientList() { Set s; synchronized (m_clientData) { s = m_clientData.keySet(); } return s.toArray(); } private class ClientInfo { String userName = "Anonymous"; int speed = 1500; HashMap files = new HashMap(); } 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); 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; } } } catch (Exception e) { } finally { synchronized (m_clientData) { m_clientData.remove(m_clientIP); } } } } private String performSearch(int depth, String query) { String results = ""; String querylc = query.toLowerCase(); 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 clients = m_clientData.keySet(); for (String clientIP : clients) { HashMap files = m_clientData.get(clientIP).files; Set clientFiles = files.keySet(); for (String fileName : clientFiles) { String fnamelc = fileName.toLowerCase(); if ( (fnamelc.indexOf(querylc) >= 0) || (files.get(fileName).toLowerCase().indexOf(querylc) >= 0) ) { results += clientIP + "|" + 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; } }