Package p2pradio

Source Code of p2pradio.Peer

/*
* P2P-Radio - Peer to peer streaming system
* Project homepage: http://p2p-radio.sourceforge.net/
* Copyright (C) 2003-2004 Michael Kaufmann <hallo@michael-kaufmann.ch>
*
* ---------------------------------------------------------------------------
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
* ---------------------------------------------------------------------------
*/

package p2pradio;

import p2pradio.logging.*;
import p2pradio.players.ListenBuffer;
import p2pradio.sources.BroadcastBuffer;
import p2pradio.packets.*;
import p2pradio.packets.security.*;
import java.io.*;
import java.net.*;
import java.util.*;


/**
* A server or a normal peer in the P2P network.
* It starts the threads and manages the buffer, the supplier and the children.
*
* @author Michael Kaufmann
*/
public class Peer extends RemotePeer
{
  // Der Server (die Wurzel des Baums)
  private RemotePeer server = null;
 
  // Ist dieser Peer der Server?
  private boolean isServer = false;
 
  // Maximale Upload-Bandbreite
  private int maxUploadBandwidth;
 
  // Der "Zulieferer"-Peer des Datenstroms
  private RemotePeer supplier = null;
  private RemotePeer supplierFather = null;
 
  private Socket supplierSocket;
  private DataInputStream supplierInputStream;
  private DataOutputStream supplierOutputStream;
 
  private Vector children = new Vector();
  private Map childrenData = new HashMap();
  private Vector bannedPeers = new Vector();
 
  private Random random = new Random();
 
  // Soll sich der Peer fies verhalten?
  private boolean misbehavior[] = new boolean[p2pradio.monitor.Commands.LAST_COMMAND];
  public static final long MISBEHAVIOR_PACKET_DELAY = 1000;
 
  // Das Monitor-Objekt dieses Peers
  private MonitorLogHandler monitorLogHandler;
   
  // War der Peer schon einmal verbunden?
  private boolean wasOnceConnected = false;
 
  // Sockets
  private DatagramSocket udpSocket = null;
  private ServerSocket tcpSocket = null;
  
  // Puffer
  private Buffer buffer;
  private BroadcastBuffer broadcastBuffer;
 
  // Threads
  private UDPDispatcher udpDispatcher;
  private TCPListener tcpListener;
  private JoinThread joinThread;
  private FreeloaderForgetter freeloaderForgetter;
  private TCPDispatcherForSupplier tcpDispatcherForSupplier;
 
 
  public static final int DEFAULT_PORT_NR = 2000;
  public static final int STREAM_PORT_OFFSET = 1;
  public static final int WEBINTERFACE_PORT_OFFSET = 2;
 
  public static final int MONITOR_PORT = 39491;
 
  public static final int MAX_FREELOADER_COMPLAINTS = 3;
  public static final int MAX_NUMBER_OF_CHILDREN = 2;
 
  // Authentifizierung
  private SignatureGenerator signatureGenerator;
  private SignatureChecker signatureChecker;
  public static boolean signStreamPackets = false;
  public static boolean verifyStreamPackets = false;
 
  protected Peer(RemotePeer server, int myPort, boolean isServer, int maxUploadBandwidth, InetSocketAddress monitorAddress) throws PeerException
  {
    super(null);
   
    try
    {
      InetSocketAddress ownAddress = new InetSocketAddress(InetAddress.getLocalHost(), myPort);
      setSocketAddress(ownAddress);
    }
    catch (UnknownHostException e)
    {
      // Sollte nicht vorkommen
      Logger.severe("Peer", "INTERNAL_ERROR", e); //$NON-NLS-1$ //$NON-NLS-2$
    }
   
    this.isServer = isServer;
    this.server = server;
    setMaxUploadBandwidth(maxUploadBandwidth);
 
    // TCP-Socket zuerst erstellen, nachher weiss man die eigene IP-Adresse
    try
    {
      tcpSocket = new ServerSocket(myPort);
    }
    catch (Exception e)
    {
      throw new PeerException(Messages.getString("COULD_NOT_CREATE_TCP_SERVERSOCKET")); //$NON-NLS-1$
    }
   
    try
    {
      udpSocket = new DatagramSocket(myPort);
    }
    catch (Exception e)
    {
      throw new PeerException(Messages.getString("COULD_NOT_CREATE_UDP_SOCKET")); //$NON-NLS-1$
    }
   
    // Monitor starten
    monitorLogHandler = new MonitorLogHandler(this);
    monitorLogHandler.setFormatter(new LogFormatter());
    Logger.getLogger().addHandler(monitorLogHandler);
   
    if (Radio.enableMonitor)
    {
      if (monitorAddress != null)
      {
        monitorLogHandler.setMonitorAddress(monitorAddress);
      }
    }
   
    // Authentifizierung
    if (signStreamPackets && isServer)
    {
      signatureGenerator = new SignatureGenerator();
    }
   
    // Puffer
    buffer = new Buffer(signatureGenerator);
   
    // UDP-Dispatcher initialisieren
    udpDispatcher = new UDPDispatcher(this, udpSocket);
    udpDispatcher.setDaemon(!isServer);
   
    // TCP-Listener initialisieren
    tcpListener = new TCPListener(this, tcpSocket);
    tcpListener.setDaemon(!isServer);
   
    // FreeloaderForgetter initialisieren und gleich starten
    // (Der tut sowieso fast nichts)
    freeloaderForgetter = new FreeloaderForgetter(this);
    freeloaderForgetter.start();
   
    // Dem Netz beitreten, falls dieser Peer kein Server ist
    if (!isServer)
    {
      Logger.info("Peer", "Peer.TRYING_TO_FIND_SUPPLIER"); //$NON-NLS-1$ //$NON-NLS-2$
      join();
    }
   
    // Dispatcher starten, falls dieser Peer der Server ist
    // Falls er nicht der Server ist, wird der Dispatcher nach
    // dem ersten erfolgreichen Join gestartet
    if (isServer)
    {
      udpDispatcher.start();
      tcpListener.start();
     
      Logger.fine("Peer", "Peer.SERVER_READY"); //$NON-NLS-1$ //$NON-NLS-2$
    }
  }
 
 
  // Konstruktor f�r Server
 
  /**
   * Creates a new source peer.
   *
   * @see #Peer(int,int,InetSocketAddress)
   */
  public Peer(int myPort) throws PeerException
  {
    this(null, myPort, true, 0, null);
  }
 
  // Konstruktor f�r Server mit Monitor
 
  /**
   * Creates a new source peer that sends notification messages to a monitor.
   *
   * @see #Peer(int,int,InetSocketAddress)
   */
  public Peer(int myPort, InetSocketAddress monitorAddress) throws PeerException
  {
    this(null, myPort, true, 0, monitorAddress);
  }
 
 
  // Konstruktor f�r Server mit Bandbreite
 
  /**
   * Creates a new source peer with specified bandwith.
   *
   * @see #Peer(int,int,InetSocketAddress)
   */
 
  public Peer(int myPort, int maxUploadBandwidth) throws PeerException
  {
     this(null, myPort, true, maxUploadBandwidth, null);
  }
 
  // Konstruktor f�r Server mit Bandbreite und Monitor
 
  /**
   * Creates a new source peer with specified bandwidth that
   * sends notification messages to a monitor.
   *
   * @param myPort The port number to use. myPort, (myPort+1)
   *        and (myPort+2) must be available for both TCP and UDP sockets.
   * @param maxUploadBandwidth The maximal upload bandwidth that this peer can use (in KiloBytes/s).
   * @param monitorAddress The address of the monitor to which
   *        notification packets will be sent.
   *
   * @throws PeerException If <code>myPort</code> is already occupied
   */
  public Peer(int myPort, int maxUploadBandwidth, InetSocketAddress monitorAddress) throws PeerException
  {
    this(null, myPort, true, maxUploadBandwidth, monitorAddress);
  }
 
 
  // Konstruktor f�r normalen Peer
  /**
   * Creates a normal peer that immediately joins the P2P network of the specified server.
   */
  public Peer(RemotePeer server, int myPort) throws PeerException
  {
    this(server, myPort, false, 0, null);
  }
 
  // Konstruktor f�r normalen Peer mit Bandbreite
  /**
   * Creates a normal peer that immediately joins the P2P network of the specified server. The new peer will use less bandwidth than <code>maxUploadBandwidth</code>.
   *
   * @param maxUploadBandwidth The maximal upload bandwidth that this peer can use (in KiloBytes/s).
   */
  public Peer(RemotePeer server, int myPort, int maxUploadBandwidth) throws PeerException
  {
    this(server, myPort, false, maxUploadBandwidth, null);
  }
 
  /**
   * Re-joins the P2P network
   */
  public synchronized void join()
  { 
    join(null);
  }
 
  protected synchronized void join(RemotePeer startPeer)
  {
    // Fehlt der Zulieferer �berhaupt?
    if (isServer || (supplier != null))
    {
      return;
    }
       
    if ((joinThread != null) && joinThread.isAlive())
    {
      // Der Verbindungsversuch dauert noch an
      return;
    }
   
    // (Wieder) mit dem Netz verbinden
    if (startPeer == null)
    {
      joinThread = new JoinThread(this);
    }
    else
    {
      joinThread = new JoinThread(this, startPeer);
    }
     
    Logger.fine("Peer", "Peer.JOINING"); //$NON-NLS-1$ //$NON-NLS-2$
     
    joinThread.start();
  }

  /*
  // Diese Methode wird aufgerufen, falls der alte Zulieferer
  // verschwunden ist und sich nicht anst�ndig verabschiedet hat
  // (passiert auch, wenn die Methode "leave" aufgerufen wird)
  synchronized void reConnect()
  {
    if (!keepDisconnected)
    {
      join();
    }
  }
  */
 
  /**
   * Leaves the P2P network. Use {@link #join()} to rejoin.
   */
  public synchronized void leave()
  { 
    if (isServer)
    {
      if (broadcastBuffer != null)
      {
        broadcastBuffer.removeFromYP();
      }
     
      return;
    }
   
    // Kann auch aufgerufen werden,
    // falls es keinen Zulieferer gibt
   
    // Zulieferer f�r die verbleibenden Kinder
    RemotePeer redirection;
   
    if (supplier != null)
    {
      redirection = supplier;
     
      // Den Zulieferer entfernen
      removeSupplier(true);
    }
    else
    {
      redirection = server;
    }
   
    Logger.fine("Peer", "Peer.LEAVING"); //$NON-NLS-1$ //$NON-NLS-2$
     
    // Das n�chste mal den Strom nicht wiederaufnehmen
    buffer.resetResumeSeqNr();
   
    // Den fremden Public Key l�schen
    signatureChecker = null;
   
   
    // Nachricht an die Kinder senden
   
    // In der Nachricht steht auch noch die Adresse des sich verabschiedenden
    // Peers (mit korrekter Portnummer), damit es nicht ganz so einfach ist,
    // diese Nachricht zu f�lschen
   
    for (int elementNr=0; elementNr < children.size(); elementNr++)
    {
      RemotePeer child = (RemotePeer)children.get(elementNr);
     
      try
      {
        Logger.finer("Peer", "Peer.SAYING_GOODBYE_TO_CHILD", child); //$NON-NLS-1$ //$NON-NLS-2$
     
        // Umleitung des Kinds auf den Zulieferer
        LeaveAndRedirectPacket packet = new LeaveAndRedirectPacket(redirection);
        RemotePeerData childData = getChildData(child);
       
        packet.send(childData.getOutputStream());
      }
      catch (IOException e)
      {
        Logger.fine("Peer", "IO_ERROR", e); //$NON-NLS-1$ //$NON-NLS-2$
       
        // Nicht zur�ckkehren - restliche Kinder benachrichtigen
      }
      finally
      {
        removeChild(child);
      }
    }
  }

  private void sayGoodbyeToSupplier(RemotePeer supplier)
  {
    // Nachricht an den Zulieferer senden
   
    try
    {
      Logger.finer("Peer", "Peer.SAYING_GOODBYE_TO_SUPPLIER", supplier); //$NON-NLS-1$ //$NON-NLS-2$
     
      LeavePacket packet = new LeavePacket();
      packet.send(supplierOutputStream);
    }
    catch (IOException e)
    {
      Logger.fine("Peer", "IO_ERROR", e); //$NON-NLS-1$       //$NON-NLS-2$
    }
  }
 
  protected synchronized boolean canServeAnotherPeer()
  {
    if (maxUploadBandwidth == 0)
    {
      // Unbeschr�nkte Upload-Bandbreite
     
      return (children.size() < MAX_NUMBER_OF_CHILDREN);
    }
   
    MetadataPacket metadataPacket = getBuffer().getNewestMetadataPacket();
   
    if (metadataPacket == null)
    {
      // Wenn noch keine Metadaten da sind,
      // wird nur ein Kind aufgenommen
     
      return (children.size() == 0);
    }
   
    int byterate = metadataPacket.getMetadata().getAverageByterate();
   
    // "+1", weil ein Kind dazukommen will
    return (((children.size() + 1) * byterate) / 1024) <= maxUploadBandwidth;
  }
 
  protected synchronized void addChild(RemotePeer peer) throws PeerException
  {
    if (equals(peer) || (!isServer && server.equals(peer)))
    {
      throw new IllegalArgumentException();
    }
   
    if (isChild(peer))
    {
      throw new PeerException(Messages.getString("Peer.PEER_IS_ALREADY_CHILD", peer)); //$NON-NLS-1$
    }

    children.add(peer);

    RemotePeerData remotePeerData = new RemotePeerData();
    remotePeerData.setTimeToConnect(System.currentTimeMillis() + TCPDispatcherForChildren.TIME_FOR_CONNECTION_ESTABLISHMENT);

    childrenData.put(peer, remotePeerData);
   
    Logger.finer("Peer", "Peer.NEW_PROVISIONAL_CHILD", peer); //$NON-NLS-1$ //$NON-NLS-2$
  }
 
  protected synchronized boolean isChild(RemotePeer peer)
  {
    return children.contains(peer);
  }
 
  protected synchronized void removeChild(RemotePeer child)
  {
    if (!children.contains(child))
    {
      throw new IllegalArgumentException(Messages.getString("Peer.PEER_IS_NO_CHILD", child)); //$NON-NLS-1$
    }
   
    RemotePeerData data = getChildData(child);
   
    // Das muss vorgezogen werden, damit die Threads merken,
    // dass dieses Kind gegangen ist
    data.disconnect();
    childrenData.remove(child);
    children.remove(child);
     
    if (data.hasBeenConnected())
    {
      try
      {
        data.getInputStream().close();
      }
      catch(IOException e)
      {
      }
       
      try
      {
        data.getOutputStream().close();
      }
      catch (IOException e)
      {
      }
       
      try
      {
        data.getSocket().close();
      }
      catch (IOException e)
      {
      }
    }
   
    Logger.finer("Peer", "Peer.CHILD_REMOVED", child); //$NON-NLS-1$ //$NON-NLS-2$
  }
 
  // Diese Methode darf nur verwendet werden, wenn der
  // Peer sich "fies" verh�lt
  protected synchronized void removeAllChildren()
  {
    for (int i=0; i < children.size(); i++)
    {
      removeChild((RemotePeer)children.get(i));
    }
  }
 
  protected synchronized RemotePeer getRedirectionChild() throws PeerException
  {
    if (children.size() == 0)
    {
      throw new PeerException(Messages.getString("Peer.NO_CHILD_AVAILABLE")); //$NON-NLS-1$
    }
    else
    {
      // Zuf�lliges Kind zur�ckgeben
      return (RemotePeer)children.get(random.nextInt(children.size()));
    }
  }
 
  protected synchronized RemotePeer getRedirectionChild(RemotePeer notThisPeer) throws PeerException
  {
    Vector allowedChildren = (Vector)children.clone();
    allowedChildren.remove(notThisPeer);
   
    if (allowedChildren.size() == 0)
    {
      throw new PeerException(Messages.getString("Peer.NO_CHILD_AVAILABLE")); //$NON-NLS-1$
    }
    else
    {
      // Zuf�lliges Kind zur�ckgeben
      return (RemotePeer)allowedChildren.get(random.nextInt(allowedChildren.size()));
    }
  }
   
  protected void finalize()
  {
    if (isServer)
    {
      Logger.fine("Peer", "Peer.SERVER_SHUTDOWN"); //$NON-NLS-1$ //$NON-NLS-2$
    }
   
    udpSocket.close();
  }
 
  /**
   * Returns whether this peer is a server/source.
   *
   * @return <code>true</code>, if this peer is a server, <code>false</code> otherwise
   */
  public boolean isServer()
  {
    return isServer;
  }
 
  /**
   *
   * Returns the server of the P2P network this peer is connected to.
   *
   * @return The server of the P2P network, or <code>null</code> if this peer is a server itself
   */
  public RemotePeer getServer()
  {
    return server;
  }

  /**
   * Changes the supplier. If the supplier is missing, this method has no effect.
   *  
   * @param informSupplier Whether the old supplier should be informed
   * @param reportFreeloader Whether the old supplier should be reported as freeloader
   */
  public synchronized void changeSupplier(boolean informSupplier, boolean reportFreeloader)
  {
    changeSupplier(null, informSupplier, reportFreeloader);
  }

  protected synchronized void changeSupplier(RemotePeer startPeer, boolean informSupplier, boolean reportFreeloader)
  {
    // Ist gar kein Zulieferer da?
    if (supplier == null)
    {
      return;
    }
   
    // Zulieferer entfernen
    removeSupplier(informSupplier);
   
    // Freeloader melden
    if (reportFreeloader)
    {
      reportFreeloader();
    }
   
    // Kinder benachrichtigen
    getBuffer().put(new StandByPacket());
   
   
    // Neuen Zulieferer suchen
    if (startPeer != null)
    {
      join(startPeer);
    }
    else
    {
      join();
    }
  }
 
  protected synchronized void removeSupplier(boolean informSupplier)
  {
    if (isServer || (supplier == null))
    {
      // Ein Server braucht keinen Zulieferer
      // oder es gibt gar keinen Zulieferer
      Logger.warning("Peer", "Peer.INVALID_CALL_OF_REMOVESUPPLIER"); //$NON-NLS-1$ //$NON-NLS-2$
      return;
    }
   
    Logger.finer("Peer", "Peer.LOST_SUPPLIER"); //$NON-NLS-1$ //$NON-NLS-2$
     
 
    // Der Zulieferer trennt die Verbindung sofort, falls er benachrichtigt
    // wird. Daher muss "supplier" auf null gesetzt werden, damit die Threads
    // dieses Peers erkennen k�nnen, dass der Zulieferer weg ist
   
    RemotePeer oldSupplier = supplier;
    supplier = null;
   
    // Zulieferer-Thread beenden
    tcpDispatcherForSupplier.shutdown();
   
    if (informSupplier)
    {
      // Vom Zulieferer verabschieden
      sayGoodbyeToSupplier(oldSupplier);
    }
 
    // Ressourcen freigeben 
    if (supplierInputStream != null)
    {
      try
      {
        supplierInputStream.close();
      }
      catch (IOException e)
      {
      }
    }
     
    if (supplierOutputStream != null)
    {
      try
      {
        supplierOutputStream.close();
      }
      catch (IOException e)
      {
      }
    }
       
    if (supplierSocket != null)
    {
      try
      {
        supplierSocket.close();
      }
      catch (IOException e)
      {
      }
    }
   
    // Alles M�gliche auf "null" setzen
    // Schon gemacht: supplier = null;
    supplierFather = null;
    supplierSocket = null;
    supplierInputStream = null;
    supplierOutputStream = null;
  }
 
  // Diese Methode NICHT synchronized machen (Deadlock)!
  protected void waitUntilSupplierDispatcherDies()
  {
    if (tcpDispatcherForSupplier != null)
    {
      try
     
        tcpDispatcherForSupplier.join();
      }
      catch (InterruptedException e)
      {
      }
    }
  }
 
  protected synchronized void addSupplier(RemotePeer supplier, RemotePeer supplierFather, Socket supplierSocket, DataInputStream supplierInputStream, DataOutputStream supplierOutputStream)
  {   
    if (isServer || (this.supplier != null))
    {
      // Ein Server braucht keinen Zulieferer
      // oder es gibt schon einen Zulieferer
      Logger.warning("Peer", "Peer.INVALID_CALL_OF_ADDSUPPLIER"); //$NON-NLS-1$ //$NON-NLS-2$
      return;
    }
   
    wasOnceConnected = true;
   
    this.supplier = supplier;
    this.supplierFather = supplierFather;
    this.supplierSocket = supplierSocket;
    this.supplierInputStream = supplierInputStream;
    this.supplierOutputStream = supplierOutputStream;
   
    // getMonitor().report(Events.NEW_SUPPLIER, supplier);
   
    // Den Public Key anfordern, falls dieser Peer ihn noch nicht hat
    if (verifyStreamPackets && (signatureChecker == null))
    {
      requestPublicKey();
    }
   
    // Dispatcher f�r den Zulieferer starten
    tcpDispatcherForSupplier = new TCPDispatcherForSupplier(this, supplier, supplierInputStream);
    tcpDispatcherForSupplier.start();
   
    // Falls der UDP-Dispatcher noch nicht l�uft: Ihn starten
    if (!udpDispatcher.isAlive())
    {
      udpDispatcher.start();
    }
   
    // Falls der TCP-Listener noch nicht l�uft: Ihn starten
    if (!tcpListener.isAlive())
    {
      tcpListener.start();
    }
  }
 

  /**
   * Returns the current supplier.
   *
   * @return The current supplier, or <code>null</code> if it's missing.
   */
  public RemotePeer getSupplier()
  {
    return supplier;
  }
 
 
  /**
   * Returns a vector of all children. The vector will contain {@link RemotePeer} objects.
   *
   * @return A vector of all children
   */
  public Vector getChildren()
  {
    return children;
  }
 
  /**
   * Returns a vector of all banned peers. The vector will contain {@link RemotePeer} objects.
   *
   * @return A vector of all banned peers
   */
  public Vector getBannedPeers()
  {
    return bannedPeers;
  }
 
  protected synchronized void processComplainAboutFreeloader(RemotePeer sender, RemotePeer freeloader) throws PeerException
  {
    // Sollte man nachschauen, ob sich der Sender schon mal bei diesem
    // Peer anmelden wollte?
       
    if (!isChild(freeloader) || sender.equals(freeloader))
    {
      // Da will uns jemand ver�ppeln
      throw new IllegalArgumentException(Messages.getString("Peer.INVALID_COMPLAINT")); //$NON-NLS-1$
    }
   
    if (canServeAnotherPeer())
    {
      // Solange noch Kinder aufgenommen werden k�nnen werden
      // keine Beschwerden akzeptiert
      return;
    }
   
    RemotePeerData data = getChildData(freeloader);
    data.addFreeloaderComplainant(sender);
   
    if (data.getFreeloaderComplaints() >= MAX_FREELOADER_COMPLAINTS)
    {
      bannedPeers.add(freeloader);
         
      // Nachricht an den Freeloader senden
      Logger.fine("Peer", "Peer.REDIRECTING_FREELOADER", freeloader); //$NON-NLS-1$ //$NON-NLS-2$
     
      RemotePeer redirection = null;
      try
      {
        redirection = getRedirectionChild(freeloader);
      }
      catch (PeerException e)
      {
        // Es ist kein Kind verf�gbar
        // In diesem Fall wird der Freeloader zu jenem Peer umgeleitet,
        // der die Beschwerde gesendet hat
        redirection = sender;
      }
       
      FreeloaderRedirectPacket packet = new FreeloaderRedirectPacket(redirection);
     
      RemotePeerData childData = getChildData(freeloader);
     
      try
      {
        packet.send(childData.getOutputStream());
      }
      catch (IOException e)
      {
        Logger.fine("Peer", "IO_ERROR", e); //$NON-NLS-1$ //$NON-NLS-2$
      }
     
      removeChild(freeloader);
    }
  }
 
  // Den aktuellen Zulieferer melden
  protected synchronized void reportFreeloader()
  {
    // Ist der Zulieferer die Wurzel?
    if (supplierFather != null)
    {
      reportFreeloader(supplier, supplierFather);
    }
  }
 
  protected void reportFreeloader(RemotePeer freeloader, RemotePeer freeloaderSupplier)
  { 
    // Eigenes UDP-Socket erstellen
    DatagramSocket mySocket = null;
    try
    {
      mySocket = new DatagramSocket();
    }
    catch (Exception e)
    {
      Logger.warning("Peer", "COULD_NOT_CREATE_UDP_SOCKET", e); //$NON-NLS-1$ //$NON-NLS-2$
      return;
    }
   
    // Nachricht an den Zulieferer des Freeloader senden
   
    DatagramPacket outPacket = null;
    try
    {
      Logger.fine("Peer", "Peer.REPORTING_FREELOADER", new RemotePeer[]{freeloader, freeloaderSupplier}); //$NON-NLS-1$ //$NON-NLS-2$
           
      outPacket = PacketFactory.createUDPPacket(new FreeloaderReportPacket(getSocketAddress().getPort(), freeloader), freeloaderSupplier);
      mySocket.send(outPacket);
    }
    catch (Exception e)
    {
      Logger.fine("Peer", "Peer.ERROR_WHILE_REPORTING_FREELOADER", e); //$NON-NLS-1$ //$NON-NLS-2$
     
      mySocket.close();
      return;
    }
     
    mySocket.close();
  }
 
  /**
   * Returns the data belonging to the specified child.
   */
  public synchronized RemotePeerData getChildData(RemotePeer child)
  {
    return (RemotePeerData)childrenData.get(child);
  }
 
  /**
   * Tells whether the specified peer is banned.
   */
  public synchronized boolean isPeerBanned(RemotePeer peer)
  {
    return bannedPeers.contains(peer);
  }
 
  protected synchronized RemotePeer searchChildWithAddress(InetSocketAddress address)
  {
    for (int i=0; i < children.size(); i++)
    {
      RemotePeer peer = (RemotePeer)children.get(i);
      RemotePeerData data = getChildData(peer);
     
      if (!data.hasBeenConnected())
      {
        if (peer.getSocketAddress().equals(address))
        {
          return peer;
        }
      }
    }
   
    return null;
  }
 
  protected synchronized void forgetSomeFreeloaders()
  {
    for (int i=0; i < children.size(); i++)
    {
      RemotePeer remotePeer = (RemotePeer)children.get(i);
      RemotePeerData data = getChildData(remotePeer);
     
      data.removeRandomFreeloaderComplainant();
    }
  }
 
  protected synchronized void forgetSomeBannedPeers()
  {
    if (bannedPeers.size() != 0)
    {
      bannedPeers.remove(random.nextInt(bannedPeers.size()));
    }
  }
 
  /**
   * Returns the buffer of this peer.
   */
  public Buffer getBuffer()
  {
    return buffer;
  }
 
  protected synchronized void removeUnconnectedChildren()
  {
    // Alle Kinder entfernen, die nach einer gewissen Zeit
    // noch keine TCP-Verbindung aufgebaut haben
   
    long now = System.currentTimeMillis();
   
    for (int i=0; i < children.size(); i++)
    {
      RemotePeer child = (RemotePeer)children.get(i);
      RemotePeerData data = getChildData(child);
     
      if (!data.hasBeenConnected())
      {
        if (data.getTimeToConnect() < now)
        {
          Logger.fine("Peer", "Peer.CHILD_REMOVED_CONNECT_TIMEOUT", child); //$NON-NLS-1$ //$NON-NLS-2$
          removeChild(child);
         
          // Und gleich noch auf die schwarze Liste setzen
          bannedPeers.add(child);
        }
      }
    }
  }
 
  /**
   * Returns the maximal upload bandwidth.
   */
  public synchronized int getMaxUploadBandwidth()
  {
    return maxUploadBandwidth;
  }
 
  /**
   * Sets the maximal upload bandwidth that this peer can use.
   *
   * @param KBperSec The maximal upload bandwidth (in KiloBytes/s).
   */
  public synchronized void setMaxUploadBandwidth(int KBperSec)
  {
    maxUploadBandwidth = KBperSec;
   
    if (maxUploadBandwidth != 0)
    {
      Logger.info("Peer", "Peer.BANDWIDTH_LIMIT_SET_TO", new Integer(maxUploadBandwidth)); //$NON-NLS-1$ //$NON-NLS-2$
    }
  }
 
  /**
   * Returns the monitor log handler of this peer, or <code>null</code> if there's none.
   */
  public MonitorLogHandler getMonitorLogHandler()
  {
    return monitorLogHandler;
  }
 
  protected synchronized boolean getMisbehavior(int index)
  {
    return misbehavior[index];
  }
 
  protected synchronized void setMisbehavior(int index, boolean misbehave)
  {
    misbehavior[index] = misbehave;
  }
 
  /**
   * Returns whether this peer is disconnected from the P2P
   * network. A peer is disconnected if it has no supplier and
   * it isn't trying to connect.
   * <P>
   * If the peer is a server, this method always returns <code>false</code>.
   */
  public synchronized boolean isDisconnected()
  {
    // Ein Server ist nie unverbunden
    if (isServer())
    {
      return false;
    }
    else
    {
      return ((getSupplier() == null) && (joinThread != null) && !joinThread.isAlive());
    }
  }
 
  protected synchronized boolean wasOnceConnected()
  {
    return wasOnceConnected;
  }
 
  /**
   * Returns the signature generator of this server peer.
   * If this peer isn't a server, this method returns <code>null</code>.
   */
  public SignatureGenerator getSignatureGenerator()
  {
    return signatureGenerator;
  }
 
  /**
   * Returns the signature checker (verifier) of this server peer.
   * If this peer is a server, this method returns <code>null</code>.
   */
  public SignatureChecker getSignatureChecker()
  {
    return signatureChecker;
  }
 
  protected void requestPublicKey()
  {
    // Public Key direkt vom Sender anfordern
    RemotePeer publicKeyOwner = getServer();
    DatagramSocket udpSocket;
   
    try
    {
      // Eigenes UDP-Socket erstellen
      udpSocket = new DatagramSocket();
      udpSocket.setSoTimeout(JoinThread.JOIN_REQUEST_SOCKET_TIMEOUT);
    }
    catch (Exception e)
    {
      Logger.warning("Peer", "COULD_NOT_CREATE_UDP_SOCKET", e); //$NON-NLS-1$ //$NON-NLS-2$
      return;
    }
   
    DatagramPacket requestPublicKeyPacket = null;
    try
    {
      requestPublicKeyPacket = PacketFactory.createUDPPacket(new PublicKeyRequestPacket(), publicKeyOwner);
    }
    catch (SocketException e)
    {
      Logger.warning("Peer", "COULD_NOT_CREATE_UDP_PACKET", e); //$NON-NLS-1$ //$NON-NLS-2$
      return;
    }
   
   
    boolean packetReceived = false;
    int connectTryNumber = 0;
   
    byte[] buffer = new byte[PublicKeyPacket.getMaxLength()];
    DatagramPacket inPacket = new DatagramPacket(buffer, buffer.length);
     
    while (!packetReceived && (connectTryNumber <= PacketFactory.UDP_RETRIES))
    {
      try
      {
        Logger.finer("Peer", "Peer.REQUESTING_PUBLIC_KEY"); //$NON-NLS-1$ //$NON-NLS-2$
         
        udpSocket.connect(publicKeyOwner.getSocketAddress());
        udpSocket.send(requestPublicKeyPacket);
        udpSocket.receive(inPacket);
        udpSocket.disconnect();
         
        packetReceived = true;
      }
      catch(SocketTimeoutException e)
      {
        Logger.fine("Peer", "Peer.SOCKET_TIMEOUT_PUBLIC_KEY"); //$NON-NLS-1$ //$NON-NLS-2$
         
        packetReceived = false;
        connectTryNumber++;
      }
      catch(Exception e)
      {
        Logger.fine("Peer", "Peer.PUBLIC_KEY_REQUEST_ERROR", e); //$NON-NLS-1$ //$NON-NLS-2$
                 
        break;
     
    }
   
    if (!packetReceived)
    {
      Logger.warning("Peer", "Peer.SERVER_DID_NOT_ANSWER_PUBLIC_KEY_REQUEST"); //$NON-NLS-1$ //$NON-NLS-2$
      return;
    }
 
    Packet response = PacketFactory.createPacket(inPacket);
 
    if (response instanceof PublicKeyPacket)
    {
      byte[] publicKey = ((PublicKeyPacket)response).getPublicKey();
     
      if (publicKey.length == 0)
      {
        // Server signiert die Pakete nicht
        // Dummy-Signierer verwenden, sonst wird bei jedem
        // Zuliefererwechsel erneut nach dem Public Key
        // gefragt
        signatureChecker = new SignatureCheckerDummy();
      }
      else
      {
        signatureChecker = new SignatureChecker(publicKey);
      }
    }
    else
    {
      // Nicht erwartetes Paket erhalten
      Logger.fine("Peer", "Peer.PUBLIC_KEY_REQUEST_UNEXPECTED_PACKET_RECEIVED", response); //$NON-NLS-1$ //$NON-NLS-2$
    }
  }
 
  public BroadcastBuffer getBroadcastBuffer()
  {
    if (!isServer)
    {
      return null;
    }
   
    if (broadcastBuffer != null)
    {
      return broadcastBuffer;
    }
    else
    {
      broadcastBuffer = new BroadcastBuffer(buffer, getSocketAddress().getPort());
      broadcastBuffer.start();
     
      return broadcastBuffer; 
    }
  }
 
  public ListenBuffer getListenBuffer()
  {
    return new ListenBuffer(getBuffer());
  }
}
TOP

Related Classes of p2pradio.Peer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.