package com.limegroup.gnutella; import java.net.Socket; import java.net.SocketException; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Iterator; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.limegroup.gnutella.settings.ConnectionSettings; import com.limegroup.gnutella.statistics.HTTPStat; import com.limegroup.gnutella.util.IOUtils; import com.limegroup.gnutella.util.NetworkUtils; import com.limegroup.gnutella.util.ThreadFactory; public class ConnectionDispatcher { private static final Log LOG = LogFactory.getLog(ConnectionDispatcher.class); /** * Mapping of first protocol word -> ConnectionAcceptor */ private static final Map protocols = Collections.synchronizedMap(new HashMap()); /** * The longest protocol word we understand. * LOCKING: protocols. */ private int longestWordSize = 0; /** * Retrieves the maximum size a word can have. */ public int getMaximumWordSize() { synchronized(protocols) { return longestWordSize; // currently GNUTELLA == 8 } } public void addConnectionAcceptor(ConnectionAcceptor acceptor, String [] words, boolean localOnly, boolean blocking) { Delegator d = new Delegator(acceptor, localOnly, blocking); synchronized(protocols) { for (int i = 0; i < words.length; i++) { if (words[i].length() > longestWordSize) longestWordSize = words[i].length(); protocols.put(words[i],d); } } } public void removeConnectionAcceptor(String [] words) { synchronized(protocols) { for (int i = 0; i < words.length; i++) protocols.remove(words[i]); longestWordSize = 0; for (Iterator iter = protocols.keySet().iterator();iter.hasNext();){ String word = (String) iter.next(); if (word.length() > longestWordSize) longestWordSize = word.length(); } } } /** * Dispatches this incoming connection to the appropriate manager, depending * on the word that was read. * * @param word * @param client * @param newThread */ public void dispatch(final String word, final Socket client, boolean newThread) { try { client.setSoTimeout(0); } catch(SocketException se) { IOUtils.close(client); return; } // try to find someone who understands this protocol Delegator delegator = (Delegator)protocols.get(word); // no protocol available to handle this word if (delegator == null) { HTTPStat.UNKNOWN_REQUESTS.incrementStat(); if (LOG.isErrorEnabled()) LOG.error("Unknown protocol: " + word); IOUtils.close(client); } delegator.delegate(word, client, newThread); } /** * Utility wrapper that checks whether the new protocol is * supposed to be local, and whether the reading should happen * in a new thread or not. */ private class Delegator { private final ConnectionAcceptor acceptor; private final boolean localOnly, blocking; Delegator(ConnectionAcceptor acceptor, boolean localOnly, boolean blocking) { this.acceptor = acceptor; this.localOnly = localOnly; this.blocking = blocking; } public void delegate(final String word, final Socket sock, boolean newThread) { boolean localHost = NetworkUtils.isLocalHost(sock); boolean drop = false; if (localOnly && !localHost) drop = true; if (!localOnly && localHost && ConnectionSettings.LOCAL_IS_PRIVATE.getValue()) drop = true; if (drop) { IOUtils.close(sock); return; } if (blocking && newThread) { Runnable r = new Runnable() { public void run() { acceptor.acceptConnection(word, sock); } }; ThreadFactory.startThread(r, "IncomingConnection"); } else acceptor.acceptConnection(word, sock); } } }